第五章:面向对象(上)
①static修饰的成员不能访问没有static修饰的成员。一个类如果没有构造器是不能创建实例的,因此每个类都有个默认的构造器。如果程序员为一个类提供了构造器,系统将不再为该类提供构造器了。一般类名大写,方法名小写,属性的第一个单词首字母小写,后面每个单词首字母大写。修饰符abstract和final最多只能出现其中一个,可以与static组合起来修饰方法。static是一个特殊的关键字,它修饰的成员变量表明它属于这个类本身,而不属于某个实例,因此static修饰的成员变量和方法也称为类变量、类方法。构造器修饰符可以使用public、protected或private之一,必须是与类名相同,构造器既不能定义返回值类型,也不能使用void修饰。
②this关键字总是指向调用该方法的对象,this关键字最大的作用是让类中的一个方法,访问该类里的另一个方法或实例变量。this如果出现在方法体中时,它的对象不确定,但是类型是确定的,它代表的对象只能是当前类。大部分情况下,一个方法访问该类中定义的其它方法、成员变量时,加不加this前缀的效果一样。static修饰的方法不能使用this引用,Java语法规定:静态成员不能直接访问非静态变量成员。比如在static 修饰的main方法内想访问非static修饰的方法,可以使用new一个新的类的对象来访问。
③Java里的方法不能单独存在,必须定义在类里。使用static修饰的方法属于类本身,可以使用类作为调用者,也可以使用类的对象来调用。但是没有static修饰的方法名,只能通过类的对象来调用。
④形参个数可变的方法,在定义方法时,在最后一个形参的类型后增加三点...,则表明该形参可以接受多个参数值,被当做数组处理。
public static void moreStr(int a,String ...str){
for(String s:str){
System.out.println("多参数包括:"+s);
}
}
调用方法:
moreStr(5, "大家好","我叫做扁蛋","今天是2016年10月16日9:33:06");
输出:
多参数包括:我叫做扁蛋
多参数包括:今天是2016年10月16日9:33:06
注:可变的形参只能处于形参列表的最后,且最多只能有一个长度可变的形参。传递进来的参数可以是数组。
⑤一个方法调用自身,被称为递归。同一个类中包含两个或两个以上方法的方法名相同,但形参列表不同,则被称为方法重载。至于方法的其它部分比如返回值类型、修饰符等,与方法重载没任何关系。Java调用方法时,可以忽略方法的返回值,因此只有返回值不同的两个方法不能共存(比如:void getName(String name)和String getName(String name)是不能共存的)。
⑥成员变量和局部变量:可以使用“类.类变量”和“实例.实例变量”来访问变量。在方法内,如果定义了与类的实例变量相同的属性,可以通过“this.变量”来访问类的变量。
⑦访问控制符:private(当前类访问权限);default(当前类、包访问);protected(子类、包中都可以访问,如果使用该修饰符,通常是希望子类来重写父类的这个方法);public(公共访问)。模块设计追求高内聚(尽可能把模块的内部数据、功能实现细节隐藏在模块内部独立完成,不允许外部直接干预)、低耦合(仅暴露少量的方法给外部调用)。
⑧Java常用的包:java.lang(Java语言的核心类,如String、Math、System和Thread等)java.util(包含大量工具类如接口和集合Arrays和List、Set) java.net(网络编程相关) java.io (输入/输出类和接口)java.sql(JDBC数据库编程相关) java.awt(抽象窗口工具类,用于构建图形用户界面GUI) java.swing(图形界面,构建平台无关的GUI程序)。
⑨构造器重载:同一个类中具有多个构造器,形参列表不同,被称为构造器重载。构造器的名必须相同(与类名相同)
构造器不能直接调用,必须使用new关键字来调用。使用this调用另一个重载的构造器只能在构建器中使用,而且必须作为构造器执行体的第一条语句。软件开发有一个规则:不要把相同的代码段书写两次以上。
(10)继承通过extends关键字实现,父类包含的范围总比子类大,子类不能获得父类的构造器。子类包含与父类同名方法的现象被称为方法重写(Override),也被称为方法覆盖。重载要遵循“两同两小一大”规则:方法名相同、形参列表相同,子类返回值应比父类的返回值类型更小或相同,子类方法抛出的异常应比父类抛出的异常类更小或相同,子类方法的访问权限应该比父类的更大或相同。子类不能访问父类“private”修饰的方法。
(11)super用于限定该对象调用它从父类继承得到的实例变量或方法,正如this不能出现在static修饰的方法一样,super也不能出现在static修饰的方法中。子类不会获得父类的构造器,但子类的构造器里可以调用父类构造器的初始化代码,子类构造器中使用super来调用。注意与构造器重载的this区分。注意,super调用父类构造器必须出现在子类构造器执行体的第一行,所以this和super调用不会同时出现。子类构造器总会调用父类的构造器一次,不管是否使用super显示调用或者通过构造器重载的this来调用。且父类的构造器总会在子类构造器之前执行,一直往上追溯。所有的类的超类(父类)是:java.lang.Object类。
(12)如果编译时的类型与运行时类型不一致,就可能出现所谓的多态。看一段代码:
父类:
public class Test3_BaseClass {
public int book=9;
public void base(){
System.out.println("父类的普通方法");
}
public void test(){
System.out.println("父类的被覆盖的test方法");
}
}
子类:
public class Test3_SubClass extends Test3_BaseClass{
public String book="Hello";
@Override
public void test(){
System.out.println("子类的覆盖父类的方法");
}
public void sub(){
System.out.println("子类普通方法");
}
public static void main(String[] args) {
Test3_BaseClass t3=new Test3_SubClass();
System.out.println(t3.book);//将会输出父类的book属性:9,而不是子类的Hello
t3.base();//父类的普通方法base()
t3.test();//子类的覆盖父类的方法test()
//t3.sub();//编译出错,父类并没有提供sub方法
}
}
注:1、对象的实例变量不具备多态性,这与方法不同的。因此实例变量还是父类的属性。2、对象调用的方法都是父类中有定义的方法名,除非被子类覆盖(重写)过的方法,才会调用的是子类的方法。其实子类是一种特殊的父类,子类的对象直接赋值(=号)给父类引用变量,无须任何类型转换,叫做“向上转型”,由系统自动完成。例如:Object obj="Hello"; String str=(String)obj;为了防止强制类型转换时可能出现异常,可先通过instanceof运算符来判断是否可以成功转换。如:
继承有个坏处:破坏封装。每个类应该封装它的内部信息和细节,而只暴露必要的方法给其它类调用。因此为了保证父类具有良好的封装性,不会被子类随意改变,设计父类应该遵循如下原则:①尽量隐藏父类的内部数据,设置成private访问类型;②不要让子类可以随意访问、修改父类的方法,除了使用private修饰外,比如某些方法需要被外部类调用,但又不希望子类重写该方法,可以使用final修饰符来修饰方法;如果希望方法被子类重写,但不希望被其它类自由访问,可以使用protected修饰该方法。尽量不要在父类构造器中调用将要被子类重写的方法。因为这样则变成调用子类重写后的方法,容易发生空指针异常。如果想把一个类设置成最终类,可以使用final修饰这个类,例如String类和System类,除此之外,使用private修饰这个类的所有构造器,从而保证子类无法调用该类的构造器,也就无法继承这个类了。
(13)初始化块:只能使用 static修饰符初始化块,被称之为静态初始化块。初始化块里的代码可以包含可执行性语句,包括定义局部变量,调用其它对象的方法,以及使用分支、循环语句等。Java中,总是先调用该类里的初始化块,无法通过类、对象来调用初始化块,而且总是在执行构造器之前执行,它不接受任何参数。静态初始化块,系统会在类初始化阶段执行,而不是在创建对象时才执行,因此静态初始化块总比普通初始化块先执行(不管顺序定义的前后,总是先执行静态的初始化块)。静态的初始化块也称之为类初始化块,也属于类的静态成员,同样遵循静态成员不能访问非静态成员的规则,包括实例变量和方法。如果有继承关系,则先追溯向上,执行父类的静态初始化块,再到本类的初始化块。