本文为原作者提供 PDF,本站在取得本人同意后进行整理发布

一、开发环境

1.1配置开发环境

配置开发环境是一切编程语言的基础,基础中的基础,也是最难的一步。这里推荐以下几种编译器:

1.Eclipse,难用的要死的编译器,不是很推荐

2.IDEA, 写java 的神器!用它甚至可以跳过安装jar包这一步,直接开始写java

3.VSCode, 它什么都能写,但配置环境非常麻烦

这里有 2023.1 版本的 idea 安装包和 java 的 jar 包 (jdk-8u25-windows-x64)

  • 若不用IDEA需要配置环境变量,具体请看这里 (请直接从网页中第3步开始)

  • 如果你的电脑不是windows系统......请自己上网找对应版本的环境变量配置教程

  • 这里强烈建议将文档中的代码放入电脑里自己运行试试

二、语法基础

2.1大致认识一下:

public class HelloWorld { /* 第一个Java程序 *它将输出字符串 Hello World */
public static void main(String[] args) { System.out.println("Hello World"); // 输出 Hello  World } }

2.2考试重点1:Java 标识符

Java 所有的组成部分都需要名字。

类名、变量名以及方法名都被称为标识符。

关于 Java 标识符,有以下几点需要注意:
  • 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线()开始

  • 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线()或数字的任何字符组合

  • 关键字不能用作标识符

  • 标识符是大小写敏感的

合法标识符举例:age、$salary、_value、__1_value 非法标识符举例:123abc、-salary

Java 其他基础语法与C语言类似,或者说完全一样,需要注意的是循环里没有goto,数组是对象的形式

2.3数组

这里仅说一下数组:(原作者注)

数组的两种常见初始化方式: 动态初始化(指定长度) 静态初始化(指定内容)

方式一:动态初始化

格式:

数组存储的数据类型[ ] 数组名字 = new 数组存储的数据类型[数组长度];

数组存储的数据类型 数组名字[ ] = new 数组存储的数据类型[数组长度];

数组定义格式详解:
  • 数组存储的数据类型:创建的数组容器可以存储什么数据类型。

  • [] : 表示数组。

  • 数组名字:为定义的数组起个变量名,满足标识符规范,可以使用名字操作数组。

  • new:关键字,创建数组使用的关键字。 数组存储的数据类型:创建的数组容器可以存储什么数据类型。

  • [长度]:数组的长度,表示数组容器中可以存储多少个元素。

  • 注意:数组有定长特性,长度一旦指定,不可更改。和水杯道理相同,买了一个2升的水杯,总容量就是2 升,不能多也不能少。

  • 举例: 定义可以存储3个整数的数组容器,代码如下:

int[] arr = new int[3];
int arr[] = new int[3];
 // 可以拆分
int[] arr;
 arr = new int[3];

方式二: 静态初始化 格式: 数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3…}; 举例: 定义存储1,2,3,4,5整数的数组容器。

int[] arr = new int[]{1,2,3,4,5};
 // 可以拆分
int[] arr;
 arr = new int[]{1,2,3,4,5};

方式三 :静态初始化省略格式(不能拆分) 格式: 数据类型[] 数组名 = {元素1,元素2,元素3…}; 举例: 定义存储1,2,3,4,5整数的数组容器

int[] arr = {1,2,3,4,5};

如果想要仔细学习数组,请看以上网页

三、面向对象

3.1基础概念

Java 作为一种面向对象语言。支持以下基本概念:

  • 多态

  • 继承

  • 封装

  • 抽象

  • 对象

  • 实例

  • 方法重载

这里仅说考试重点考的 对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。

类:类是一个模板,它描述一类对象的行为和状态。 这里写一个类举例:

public class Dog {
 String breed;
 int size;
 String colour;
 int age;
 void eat() {
 }
 void run() {
}
 void sleep(){
 }
 void name(){
 }
 }

一个类可以包含以下类型变量:

  • 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。

  • 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。

  • 类变量:类变量也声明在类中,方法体之外,但必须声明为 static 类型。

一个类可以拥有多个方法,在上面的例子中:eat()、run()、sleep() 和 name() 都是 Dog 类的方法。

构造方法

每个类都有构造方法。如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法。 在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。 下面是一个构造方法示例:

public class Puppy{
 public Puppy(){
 }
 public Puppy(String name){
 // 这个构造方法仅有一个参数:name
 }
 }
创建对象

对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步: 声明:声明一个对象,包括对象名称和对象类型。 实例化:使用关键字 new 来创建一个对象。 初始化:使用 new 创建对象时,会调用构造方法初始化对象。 下面是一个创建对象的例子:

public class Puppy{
 public Puppy(String name){
 //这个构造器仅有一个参数:name
 System.out.println("小狗的名字是 :" + name );
 }
 public static void main(String[] args){
 // 下面的语句将创建一个Puppy对象
Puppy myPuppy = newPuppy( "tommy" );
 }
 }
源文件声明规则

当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意这些规则。

一个源文件中只能有一个 public 类,一个源文件可以有多个非 public 类

  • 源文件的名称应该和 public 类的类名保持一致。例如:源文件中public 类的类名是 Employee,那么源文件应该命名为Employee.java。

  • 如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。

  • 如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面。

  • import 语句和 package 语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。

public class Puppy{
 int puppyAge;
 public Puppy(String name){
 // 这个构造器仅有一个参数:name
 System.out.println("小狗的名字是 : " +name );
 }
 public void setAge( int age ){
 puppyAge = age;
 }
 public int getAge( ){
 System.out.println("小狗的年龄为 : " +puppyAge );
 return puppyAge;
 }
 public static void main(String[] args){
 /* 创建对象 */
 Puppy myPuppy = newPuppy( "tommy");
 /* 通过方法来设定age*/
 myPuppy.setAge( 2 );
 /* 调用另一个方法获取age*/
 myPuppy.getAge( );
 /*你也可以像下面这样访问成员变量 */
 System.out.println("变量值 : " + myPuppy.puppyAge );
 }
 }*

这是一段类和对象的示例代码,看懂它就没问题了

3.2考试重点2:重写与重载

  • 方法重载是一个类的多态性的表现,方法重写是父类和子类的一种多态性表现

  • 方法重载是在一个类中定义多个方法名相同,而参数类型、数量或次序不同的方法。

  • 方法重写是在子类中存在与父类的方法的方法名同、参数相同、返回类型可以不同的方法。

    更具体的请看这里

四、抽象类与接口

4.1抽象类

抽象类

在 Java 语言中使用 abstractclass 来定义抽象类。如下实例: Employee.java 文件代码:

/* 文件名 :Employee.java*/
 public abstract class Employee
 {
 private String name;
 private String address;
 private int number;
 public Employee(String name, String address, int number)
 {
 System.out.println("Constructing an Employee");
 this.name = name;
 this.address = address;
 this.number = number;
 }
 public double computePay()
 {
System.out.println("Inside Employee computePay");
return 0.0;
 }
 public void mailCheck()
 {
 System.out.println("Mailing a check to " + this.name""+this.address);
}
 public String toString()
 {
 return name + " " + address + " " + number;
 }
 public String getName()
 {
 return name;
 }
 public String getAddress()
 {
 return address;
 }
 public void setAddress(String newAddress)
 {
 address = newAddress;
 }
 public int getNumber()
 {
 return number;
 }
 }

注意到该 Employee 类没有什么不同,尽管该类是抽象类,但是它仍然有 3 个成员变量,7 个成员方法和 1 个构造方法。 现在如果你尝试如下的例子: AbstractDemo.java 文件代码:

/* 文件名 :AbstractDemo.java */
 public class AbstractDemo
 {
 public static void main(String [] args)
 {
 /* 以下是不允许的,会引发错误 */
Employee e = newEmployee("George W.", "Houston, TX", 43);
 System.out.println("\n Call mailCheck using Employee reference--");
 e.mailCheck();
 }
 }*

当你尝试编译 AbstractDemo 类时,会产生如下错误:

Employee.java:46: Employee is abstract; cannot be instantiated Employee e = newEmployee("George W.", "Houston, TX", 43);

继承抽象类

我们可以通过以下方式继承 Employee 类的属性: Salary.java 文件代码:

/* 文件名 :Salary.java*/
 public class Salary extends Employee
 {
 private double salary; //Annual salary
 public Salary(String name, String address, int number, double
 salary)
 {
 }
 super(name, address, number);
 setSalary(salary);
 public void mailCheck()
 {
 System.out.println("Within mailCheck of Salary class ");
 System.out.println("Mailing check to " + getName()"with salary " + salary);
}
 public double getSalary()
 {
 return salary;
 }
 public void setSalary(double newSalary)
 {
 if(newSalary >= 0.0)
 {
salary = newSalary;
 }
 }
 public double computePay()
 {
 System.out.println("Computing salary pay for " + getName());
 return salary/52;
 }
 }*

尽管我们不能实例化一个 Employee 类的对象,但是如果我们实例化一个 Salary 类对象,该对象将从 Employee 类继承7 个成员方法,且通过该方法可以设置或获取三个成员变量。 AbstractDemo.java 文件代码:

/* 文件名 :AbstractDemo.java */
 public class AbstractDemo
 {
 public static void main(String [] args)
 {
 Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
 Employee e = newSalary("John Adams", "Boston, MA", 2, 2400.00);
 System.out.println("Call mailCheck using Salary reference--");
 s.mailCheck();
 System.out.println("\n Call mailCheck using Employee reference--");
 e.mailCheck();
 }
 }

以上程序编译运行结果如下:

Constructing an Employee
 Constructing an Employee
 Call mailCheck using Salary reference--
 Within mailCheck of Salary class
 Mailing check to Mohd Mohtashim with salary 3600.0
 Call mailCheck using Employee reference--
 Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.

抽象方法

如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。 Abstract 关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。 抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。

public abstract class Employee
 {
 private String name;
 private String address;
 private int number;
 public abstract double computePay();
 //其余代码
}

声明抽象方法会造成以下两个结果: 如果一个类包含抽象方法,那么该类必须是抽象类。 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。

继承抽象方法的子类必须重写该方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。 如果 Salary 类继承了 Employee 类,那么它必须实现 computePay()方法: Salary.java 文件代码:

/* 文件名 :Salary.java*/
 public class Salary extends Employee
 {
 private double salary; // Annual salary
 public double computePay()
 {
 System.out.println("Computing salary pay for " + getName());
 return salary/52;
 }
 //其余代码
}

抽象类总结规定
  • 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。

  • 抽象类中不一定包含抽象方法,但是有抽象方法的类必定**是抽象类**。

  • 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。

  • 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。

  • 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

4.2接口

接口:
  • 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

  • 接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。

  • 除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。

  • 接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

接口与类相似点:
  • 一个接口可以有多个方法。

  • 接口文件保存在 .java 结尾的文件中,文件名使用接口名。

  • 接口的字节码文件保存在 .class 结尾的文件中。

  • 接口相应的字节码文件必须在与包名称相匹配的目录结构中。

接口与类的区别:
  • 接口不能用于实例化对象。

  • 接口没有构造方法。

  • 接口中所有的方法必须是抽象方法,Java8 之后 接口中可以使用 default 关键字修饰的非抽象方法。

  • 接口不能包含成员变量,除了 static 和 final 变量。

  • 接口不是被类继承了,而是要被类实现。

  • 接口支持多继承。

接口特性
  • 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为publicabstract(只能是 publicabstract,其他修饰符都会报错)。

  • 接口中可以含有变量,但是接口中的变量会被隐式的指定为public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。

  • 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。

4.3考试重点3 抽象类和接口的区别

  • 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。

  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是publicstaticfinal 类型的。

  • 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。

  • 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

接口的声明

接口的声明语法格式如下: [访问修饰符]interface 接口名称 [extends 其他的接口名]{// 声明变量 // 抽象方法 }

Interface 关键字用来声明一个接口。下面是接口声明的一个简单例子。

NameOfInterface.java 文件代码:

/* 文件名 : NameOfInterface.java */ import java.lang.*; // 引 入 包 
​
public interface NameOfInterface { //任何类型 final, static 字段 //抽象方法 }

接口有以下特性:
  • 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract 关键字。

  • 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract 关键字。

  • 接口中的方法都是公有的。

实例

Animal.java 文件代码:

/* 文件名 :Animal.java*/ interface Animal { public void eat(); public void travel(); }

文件名 : MammalInt.java

public class MammalInt implements Animal{
     public void eat(){
     System.out.println("Mammal eats");
     }
     public void travel()
     { System.out.println("Mammal travels"); }
     public int noOfLegs(){ return 0; }
     public static void main(String args[])
     {
     MammalInt m = new MammalInt();
     m.eat(); m.travel(); }
     }

以上实例编译运行结果如下: MammaleatsMammal travels

重写接口中声明的方法时,需要注意以下规则:
  • 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常

  • 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。

  • 如果实现接口的类是抽象类,那么就没必要实现该接口的方法。

在实现接口的时候,也要注意一些规则:
  • 一个类可以同时实现多个接口。

  • 一个类只能继承一个类,但是能实现多个接口。

  • 一个接口能继承另一个接口,这和类之间的继承比较相似。接口的继承

  • 一个接口能继承另一个接口,和类之间的继承方式比较相似。

  • 接口的继承使用extends关键字,子接口继承父接口的方法。

下面的Sports接口被Hockey和Football接口继承:

// 文件名:Sports.java
 public interface Sports
 {
 public void setHomeTeam(String name);
 public void setVisitingTeam(String name);
 }
 // 文件名:Football.java
 public interface Football extends Sports
 {
 public void homeTeamScored(int points);
 public void visitingTeamScored(int points);
 public void endOfQuarter(int quarter);
 }
// 文件名:Hockey.java
 public interface Hockey extends Sports
 {
 public void homeGoalScored();
 public void visitingGoalScored();
 public void endOfPeriod(int period);
 public void overtimePeriod(int ot);
 }

Hockey 接口自己声明了四个方法,从Sports接口继承了两个方法,这样,实现Hockey接口的类需要实现六个方法。相似的,实现Football接口的类需要实现五个方法,其中两个来自于Sports接口。

接口的多继承

在Java中,类的多继承是不合法,但接口允许多继承。 在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口。 如下所示:

public interface Hockey extends Sports, Event

以上的程序片段是合法定义的子接口,与类不同的是,接口允许多继承,而 Sports及 Event 可以定义或是继承相同的方法

标记接口

最常用的继承接口是没有包含任何方法的接口。 标记接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。

标记接口作用:

简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。

例如:java.awt.event 包中的 MouseListener 接口继承的 java.util.EventListener 接口定义如下:

package java.util; public interface EventListener {}

没有任何方法的接口被称为标记接口。

标记接口主要用于以下两种目的:

建立一个公共的父接口:

正如EventListener 接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。

向一个类添加数据类型:

这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。

五、异常

异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。比如说,你的代码少了一个分号,那么运行出来结果提示是错误 java.lang.Error;如果你用 System.out.println(11/0)那么你是因为你用 0 做了除数,会抛出java.lang.ArithmeticException 的异常。

异常发生的原因有很多,通常包含以下几大类:
  • 用户输入了非法数据。

  • 要打开的文件不存在。

  • 网络通信时连接中断,或者JVM内存溢出。

  • 这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。

要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:
  • 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。

  • 运行时异常 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。

  • 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

Exception 类的层次
  • 所有的异常类是从 java.lang.Exception 类继承的子类。

  • Exception 类是 Throwable 类的子类。除了Exception 类外,Throwable 还有一个子类Error 。

  • Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。Error 用来指示运行时环境发生的错误。

例如,JVM 内存溢出。一般地,程序不会从错误中恢复。 异常类有两个主要的子类:IOException 类 和RuntimeException 类。

捕获异常

使用 trycatch 关键字可以捕获异常。try/catch 代码块放在异常可能发生 的地方。 try/catch 代码块中的代码称为保护代码,使用 try/catch 的语法如下:

try
 {
 // 程序代码
}catch(ExceptionName e1)
 {
 //Catch 块
}

Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try后面的 catch 块就会被检查。 如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。

实例

下面的例子中声明有两个元素的一个数组,当代码试图访问数组的第四个元素的时候就会抛出一个异常。 ExcepTest.java 文件代码:

// 文件名 : ExcepTest.java
 import java.io.*;
 public class ExcepTest{
 public static void main(String args[]){
 try{
 int a[] = new int[2];
 System.out.println("Access element three :" + a[3]);
 }catch(ArrayIndexOutOfBoundsException e){
 System.out.println("Exception thrown :" + e);
 }
 System.out.println("Out of the block");
 }
 }

以上代码编译运行输出结果如下: Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3 Out of the block

多重捕获块

一个 try 代码块后面跟随多个 catch 代码块的情况就叫多重捕获。

多重捕获块的语法如下所示:
try{
 // 程序代码
}catch(异常类型1 异常的变量名1){
 // 程序代码
}catch(异常类型2 异常的变量名2){
 // 程序代码
}catch(异常类型3 异常的变量名3){
 // 程序代码
}

上面的代码段包含了 3 个 catch块。

  • 可以在 try 语句后面添加任意数量的 catch 块。

  • 如果保护代码中发生异常,异常被抛给第一个 catch 块。

  • 如果抛出异常的数据类型与 ExceptionType1 匹配,它在这里就会被捕获。

  • 如果不匹配,它会被传递给第二个 catch 块。

  • 如此,直到异常被捕获或者通过所有的 catch 块。

实例

该实例展示了怎么使用多重 try/catch。

try {
 file = new FileInputStream(fileName);
 x = (byte) file.read();
 } catch(FileNotFoundException f) { // Not valid!
 f.printStackTrace();
 return-1;
 } catch(IOException i) {
 i.printStackTrace();
 return-1;
 }
throws/throw 关键字

在Java中, throw 和 throws 关键字是用于处理异常的。 throw 关键字用于在代码中抛出异常,而 throws 关键字用于在方法声明中指定可能会抛出的异常类型。

throw 关键字

throw 关键字用于在当前方法中抛出一个异常。 通常情况下,当代码执行到某个条件下无法继续正常执行时,可以使用 throw 关键字抛出异常,以告知调用者当前代码的执行状态。

例如,下面的代码中,在方法中判断 num 是否小于 0,如果是,则抛出一个IllegalArgumentException 异常。 实例

public void checkNumber(int num) {
 if (num < 0) {
 throw new IllegalArgumentException("Number must be positive");
 }
 }

throws 关键字 throws 关键字用于在方法声明中指定该方法可能抛出的异常。当方法内部抛出指定类型的异常时,该异常会被传递给调用该方法的代码,并在该代码中处理异常。

例如,下面的代码中,当 readFile 方法内部发生 IOException 异常时,会将该异常传递给调用该方法的代码。在调用该方法的代码中,必须捕获或声明处IOException 异常。 实例

public void readFile(String filePath) throws IOException {
 BufferedReader
 reader
 FileReader(filePath));
 String line = reader.readLine();
 while (line != null) {
 System.out.println(line);
 line = reader.readLine();
 }
 reader.close();
 }

一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。 例如,下面的方法声明抛出 RemoteExceptionInsufficientFundsException

import java.io.*;
 public class className
 {
 public void withdraw(double amount) throws RemoteException,
 InsufficientFundsException
 {
 // Method implementation
 }
 //Remainder of class definition
 }

finally 关键字 finally 关键字用来创建在 try 代码块后面执行的代码块。无论是否发生异常,finally 代码块中的代码总会被执行。 在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。finally 代码块出现在 catch 代码块最后,语法如下:

try{
 // 程序代码
}catch(异常类型1 异常的变量名1){
 // 程序代码
}catch(异常类型2 异常的变量名2){
 // 程序代码
}finally{
 // 程序代码
}
实例

ExcepTest.java 文件代码:

public class ExcepTest{
 public static void main(String args[]){
 int a[] = new int[2];
 try{
 System.out.println("Access element three :" + a[3]);
 }catch(ArrayIndexOutOfBoundsException e){
 System.out.println("Exception thrown :" + e);
 }
 finally{
 a[0] = 6;
 System.out.println("First element value: " +a[0]);
 System.out.println("The finally statement is executed");
 }
 }
 }

以上实例编译运行结果如下: Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3 First element value: 6 The finally statement is executed

注意下面事项:
  • catch 不能独立于 try 存在。

  • 在 try/catch 后面添加 finally 块并非强制性要求的。

  • try 代码后不能既没 catch 块也没 finally 块。

  • try, catch, finally 块之间不能添加任何代码。

六、泛型与集合

Java 泛型(generics)是 JDK5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

假定我们有这样一个需求:写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,该如何实现?

答案是可以使用 Java 泛型。

使用 Java 泛型的概念,我们可以写一个泛型方法来对一个 对象数组排序。然后,调用该泛型方法来对整型数组、浮点 数数组、字符串数组等进行排序。

泛型方法

你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

下面是定义泛型方法的规则:
  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的 )。

  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。

  • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。

  • 泛型方法体的声明和其他方法一样。注意类型参数只能代表

  • 引用型类型,不能是原始类型(像 int、double、char 等)。

java 中泛型标记符:
  • E- Element (在集合中使用,因为集合中存放的是元素)

  • T- Type(Java 类)

  • K- Key(键)

  • V- Value(值)

  • N-Number(数值类型)

  • ?- 表示不确定的 java 类型

实例

下面的例子演示了如何使用泛型方法打印不同类型的数组元素: 实例

public class GenericMethodTest
 {
 // 泛型方法 printArray
 public static < E > void printArray( E[] inputArray )
 {
 // 输出数组元素
for ( E element : inputArray ){
 System.out.printf( "%s ", element );
 }
 System.out.println();
 }
 public static void main( String args[] )
 {
 // 创建不同类型数组: Integer,Double 和 Character
 Integer[] intArray = { 1, 2, 3, 4, 5 };
 Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
 Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
 System.out.println( "整型数组元素为:" );
 printArray( intArray ); // 传递一个整型数组
System.out.println( "\n 双精度型数组元素为:");
 printArray( doubleArray ); // 传递一个双精度型数组
System.out.println( "\n 字符型数组元素为:" );
 printArray( charArray ); // 传递一个字符型数组
}
 }

编译以上代码,运行结果如下所示:

整型数组元素为:
 12345
双精度型数组元素为:
 1.1 2.2 3.3 4.4
字符型数组元素为:
 HELLO
有界的类型参数:

可能有时候,你会想限制那些被允许传递到一个类型参数类型种类范围。例如,一个操作数字的方法可能只希望接受Number 或者Number子类的实例。这就是有界类型参数的目的。

要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends 关键字,最后紧跟它的上界。 实例 下面的例子演示了"extends"如何使用在一般意义上的意思"extends"(类)或者"implements"(接口)。该例子中的泛型方法返回三个可比较对象的最大值。

实例

public class MaximumTest
 {
 // 比较三个值并返回最大值
public static > T maximum(T x, T y, T z)
 {
 T max=x;// 假设x是初始最大值
if ( y.compareTo( max ) > 0 ){
 max=y; //y 更大
}
 if ( z.compareTo( max ) > 0 ){
 max=z; // 现在 z 更大
}
 return max; // 返回最大对象
}
 public static void main( String args[] )
 {
 System.out.printf( "%d, %d 和 %d 中最大的数为 %d\n\n",
 3, 4, 5, maximum( 3, 4, 5 ) );
 System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f\n\n",
 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
 System.out.printf( "%s, %s 和 %s 中最大的数为 %s\n","pear",
 "apple", "orange", maximum( "pear", "apple", "orange" ) );
}
 }

编译以上代码,运行结果如下所示:

3, 4 和 5 中最大的数为 5
6.6, 8.8 和 7.7 中最大的数为 8.8
pear, apple 和 orange 中最大的数为 pear
泛型类

泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。

因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。

实例

如下实例演示了我们如何定义一个泛型类:

public class Box {
 private T t;
public void add(T t) {
 this.t = t;
 }
 public T get() {
 return t;
 }
 public static void main(String[] args) {
 Box integerBox = new Box();
 Box stringBox = new Box();
 integerBox.add(new Integer(10));
 stringBox.add(new String("教程"));
 System.out.printf("整型值为 :%d\n\n", integerBox.get());
 System.out.printf("字符串为 :%s\n", stringBox.get());
 }
 }

编译以上代码,运行结果如下所示:

整型值为 :10
字符串为 : 教程
类型通配符
类型通配符一般是使用 ? 代替具体的类型参数。例如List 在逻辑上是 List,List 等所有 List<具体类型实参> 的父类类。
实例

import java.util.*;
public class GenericTest {
 public static void main(String[] args) {
 List name = new ArrayList();
 List age = new ArrayList();
 List number = new ArrayList();
 name.add("icon");
 age.add(18);
 number.add(314);
 getData(name);
 getData(age);
 getData(number);
 }
 public static void getData(List data) {
 System.out.println("data :" + data.get(0));
 }
 }

输出结果为:

data :icon
 data :18
 data :314

解析: 因为 getData() 方法的参数是 List 类型的,所以name,age,number 都可以作为这个方法的实参,这就是通配符的作用。

类型通配符上限通过形如List来定义,如此定义就是通配符泛型值接受Number及其下层子类类型。
实例

import java.util.*;
 public class GenericTest {
 public static void main(String[] args) {
 List name = new ArrayList();
 List age = new ArrayList();
 List number = new ArrayList();
 name.add("icon");
 age.add(18);
 number.add(314);
 //getUperNumber(name);//1
 getUperNumber(age);//2
 getUperNumber(number);//3
 }
 public static void getData(List data) {
 System.out.println("data :" + data.get(0));
 }
 public static void getUperNumber(List data) {
 System.out.println("data :" + data.get(0));
 }
 }

输出结果:

data :18
data :314

解析: 在 //1 处会出现错误,因为 getUperNumber() 方法中的参数已经限定了参数泛型上限为 Number,所以泛型为String 是不在这个范围之内,所以会报错。

类型通配符下限通过形如 List 来定义,

表示类型只能接受 Number 及其上层父类类型,如 Object类型的实例。 至于集合,记住书上常用的几个,会用就行,若要深入学习,请看这里

七、文件操作

看吧,前面都学好的话,这章没啥好说的,就是调用人家写好的 类或函数

八、Jdbc

Jdbc:Java DataBase Connectivity(Java 语言连接数据库)

这是学习javaweb的基础,对以后的学习非常重要,但是,考试只考连接数据库的步骤,故此处不多说其他的 想深入学习的话,建议先学mysql

public class ConnectionTest {
 public static void main(String[] args) {
 Connection conn = null;
 Statement stmt = null;
 try {
 //
注册驱动
Driver driver = new com.mysql.cj.jdbc.Driver();
 DriverManager.registerDriver(driver );
 //获取链接
// 127.0.0.1 主机地址表示本机,3306 数据库端口号,test:数据库名
称 问号部分表示时区,有的数据库版本可不加
String  url ="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT";
 //root 数据库连接名
String user= "root";
 //数据库密码
String password = "123456";
 conn = DriverManager.getConnection(url,user,password);
 System.out.println("数据库连接对象"+conn);
 //
获取数据库操作对象(Statement专门执行SQL语句的)
stmt = conn.createStatement();
 //
执行SQL
 String sql = "insert into student(id) values(1)";
 //专门执行DML语句返回值是数据库中记录条数
int count = stmt.executeUpdate(sql);
 System.out.println(count == 1?"保存成功":"保存失败");
 } catch (Exception e) {
 e.printStackTrace();
 //释放资源
//
为了保证资源一定释放。在finally语句块关闭资源并且从小到
依次关闭,必须分开try
 }finally{
 if(stmt != null){
 try {
 stmt.close();
 } catch (SQLException throwables) {
 throwables.printStackTrace();
 }
 }
 if(conn != null){
 try {
conn.close();
 } catch (SQLException throwables) {
 throwables.printStackTrace();
 }
 }
 //通过coon连接对象开启stmt,就得先关闭stmt
 }
 }