写这篇博客是为了复习一下Java语言的重要知识点。工作上用到的是Java,所以很有必要再好好复习一下Java基础。争取每天写一点,做到知识点的回顾,加深印象。
参考书:
Java核心技术
Java编程思想等
JDK环境配置
环境配置不过多复习了,主要在于环境变量的配置。可以上网查资料。
Java基本语言
数据类型
Java中共有8种:byte,short,int,long,float,double,char,boolean
输入输出
输入
首先构造一个Scanner对象,并与标准输入流System.in关联:
1 | Scanner in = new Scanner(System.in); |
输出
1 System.out.println(str);
文件输入与输出
要想对文件进行读取,就需要一个用File对象构造一个Scanner对象:1
Scanner in = new Scanner(new File("myFile.txt"));
如果文件名中包含反斜杠符号,就要在每个反斜杠之前再加上一个额外的反斜杠:
“c:\mydirectory\myFile.txt”
要想写入文件,就需要构造一个PrintWriter对象。在构造器中,只需要提供文件名:1
PrintWriter out = new PrintWriter("myFile.txt");
如果文件不存在,则可以像输出到System.out一样,使用print命令。
控制流程
- 条件语句:if…else…
- 循环语句:while,do…while,for
- 多重选择:switch
- 中断控制流程语句:break,continue
- For each循环:
实例:1
2for(int element: a)
System.out.println(element);
打印数组a的每一个元素,一个元素占一行。
for each 循环语句的循环变量将会遍历数组中的每个元素,而不需要使用下标值。
面向对象方面
类:是构造对象的模板或蓝图。由类构造对象的过程称为创建类的实例。
封装:将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式。对象中的数据称为实例域,操纵数据的过程称为方法
对象:具有状态、行为和标识。这意味着每一个对象都可以拥有内部数据(它们给出了该对象的状态)和方法(它们产生行为),并且每一个对象都可以唯一地与其他对象区分开来,具体说就是每一个对象在内存中都有一个唯一的地址。
对象之间的关系:
依赖(dependence):即”uses-a”关系。例如:Order类使用Account类是因为Order对象需要访问Account对象来查看信用状态。在实际编程中应该尽可能地将相互依赖的类减少到最小,也就是让类之间的耦合度最小
聚合(aggregation):也称为关联。即”has-a”关系例如:一个Order对象包含一些Item对象。聚合关系意味着类A的对象包含类B的对象。
继承(inheritance):即”is-a”关系,是用于表示特殊与一般的关系。例如RushOrder类由Order类继承而来
参数传递:
按值调用:表示方法接收的是调用者提供的值
按引用调用:表示方法接收的是调用者提供的变量地址。
一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。1
2
3
4
5double precent = 10;
harry.raiseSalary(precent);
public static void raiseSalary(double x) {
x = 3 * x;
}
可以看到,最终precent的值仍为10,而x=30的
然而,方法的参数有两种类型:
- 基本数据类型(数字、布尔值)
- 对象引用
1 | harry = new Employee(); |
这里最终Harry的薪水变为原来的2倍了,它的值发生了改变。
总结:
- 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)
- 一个方法可以改变一个对象参数的状态
- 一个方法不能让对象参数引用一个新的对象
重载:
如果多个方法有相同的名字、不同的参数,遍产生了重载。
编译器通过用各个方法给出的参数类型与特定方法的调用所使用的值类型进行匹配来挑选出相应的方法。如果找不到匹配的参数或者找到多个匹配的参数,就会产生编译错误。
方法的签名:要完整描述一个方法必须指出方法名以及参数类型,这叫做方法的签名。如:
indexOf(int) indexOf(int,int) indexOf(String) indexOf(String,String)
返回类型不是方法签名的一部分,也就是说,不能有两个名字相同、参数类型也相同缺返回不同类型值的方法。
无参数的构造器:
如果在编写一个类时没有编写构造器,那么系统就会提供一个无参数构造器。这个构造器就会将所有的实例域设置为默认值。
数值型数据设置为0,布尔型数据设置为false,所有对象变量将设置为null。
如果类中提供了至少一种构造器,但是没有提供无参数的构造器,则在构造对象时如果没有提供参数就会被视为不合法。
仅当类没有提供任何构造器时,系统才会提供一个默认的构造器。
如果构造器的第一个语句形如:this(…),这个构造器将调用同一类的另一个构造器
1 | public Employee{ |
当调用new Employee(100)时,Employee(double)构造器将调用Employee(String,double)构造器
初始化块:
在一个类的声明中,可以包含多个代码块,只要构造对象,这些代码块就会被执行。
首先运行初始化块,然后才运行构造器的主体部分。
1 | class Employee{ |
调用构造器的具体处理步骤:
(1)所有数据域被初始化为默认值(0、false、null)
(2)按照在类声明中出现的顺序,一次执行所有域初始化语句和初始化块
(3)如果构造器第一行调用了第二个构造器,则执行第二个构造器主体
(4)执行这个构造器主体
tips:
类设计技巧:
- 一定要保证数据私有。绝对不要破坏封装性
- 一定要对数据初始化
- 不要在类中使用过多的基本类型
- 不是所有的域都需要独立的域访问器和域更改器
- 将职责过多的类进行分解
- 类名和方法名要能够体现它们的职责
继承:
在子类中可以增加域、方法或覆盖父类的方法,但是不能删除继承的任何域和方法。
1 | public Manager(String n, double s, int year, int month, int day){ |
super(n,s,year,month,day)是”调用父类Employee中含有n,s,year,month,day参数的构造器”的简写方式。
使用super调用构造器的语句必须是子类构造器的第一条语句
如果子类的构造器没有显式地调用父类的构造器,则将 自动地调用父类默认(没有参数的)构造器。如果父类没有不带参数的构造器,并且在子类的构造器中又没有显式地调用父类的其他构造器,则Java编译器将报告错误。
java不支持多继承,一个子类只能继承一个父类。但是一个父类可以有多个子类。
对象方法调用的执行过程:
(1)编译器查看对象的声明类型和方法名:
假设调用x.f(param),且隐式参数x声明为C类的对象。需要注意的是:有可能存在多个名字为f,参数类型不一样的方法,如f(int)和f(String)。此时编译器会一一列举所有C类中名为f的方法和其父类中访问属性为public且名为f的方法
(2)接下来,编译器会查看调用方法时提供的参数类型。如果在所有名为f的方法中 存在一个与提供的参数类型完全匹配,就选择这个方法。这个过程被称为重载解析(overloading resolution),如果没有找到匹配的方法,就会报告一个错误
(3)如果是private方法、static方法、final方法或者构造器,那么编译器将可以准确知道调用哪个方法,将这种调用方式称为静态绑定。与此对应的是,调用的方法依赖于隐式参数的实际类型,并且在运行时实现动态绑定。
(4)当程序运行,并且采用动态绑定调用方法时,虚拟机一定调用与x所引用对象的实际类型最合适的那个类的方法。
每次调用方法都要进行搜索,时间开销相当大,因此,虚拟机预先为每个类创建了一个方法表(method table),其中列出了所有方法的签名和实际调用的方法。这样一来,在实际调用方法时,虚拟机只需要查询一下方法表就可以了。
在覆盖一个方法时,子类方法不能低于父类方法的可见性。特别是父类方法为public时,子类方法一定是public
当一个类用final修饰时,就不允许被继承了,当一个类中的某个方法被final修饰了,子类就不能覆盖这个方法了。
对象的强制类型转换:
- 只能在继承层次内进行类型转换
- 在将超类转换成子类之前,应该使用instanceof进行检查。
instanceof运算符是用来在运行时指出对象是否是特定类的一个实例,它会根据结果返回一个布尔值,是-true,否-false
抽象类:用abstract关键字修饰的类。
抽象类中至少有一个抽象方法,可以存在非抽象方法,即可以包含具体数据和具体方法。抽象方法在抽象类中充当占位的角色,它们的具体实现在子类中。抽象类不能被实例化。