继承的基本概念
继承的注意事项
代码块
子类构造器
多态
抽象
方法调用的过程
Object类
equals()方法与hashCode()方法
toString()方法
泛型数组列表——ArrayList类
对象包装器
继承的设计技巧
1.继承的基本思想是基于已有的类创造新的类。
2.反射是指在程序运行期间更多地了解类及其属性的能力。
3.关键字extend表示正在构造的新类派生于一个已存在的类,用法如下:
public class A {
// methods and fields
}
public class B extends A {
// added methods and fields
}
其中,这个已经存在的类成为超类、基类或父类,新类成为子类、派生类或孩子类。常用的名词为超类和子类。
4.一个对象变量可以指示多种实际类型的现象称为多态。在运行时能够自动选择适当的方法,称为动态绑定。
5.不允许扩展的类称为final类,final类不可以被定义子类,这是阻止继承的一种方法。
6.如果一个方法没有被覆盖并且很短,编译器就可以对其进行优化处理,这个过程称为内联。
1.Java中,所有的继承都是公有继承。
2.子类无需显示定义超类的方法和字段,即只需指出子类与超类的不同之处。
3.应将最一般的方法放在超类中,将特殊方法放在子类中。
4.子类方法不可以访问超类的私有字段,需要与其他方法一样使用公有接口。
5.覆盖方法指超类和子类中同名但功能不同的方法:
例如:
public class A {
// methods and fields
public void func1() {
// do something
}
}
public class B extends A {
// added methods and fields
public void func1() {
super.func1();
// do something
}
}
6.super与C++的this并不相同,super不是一个对象的引用。
7.Java中动态绑定是默认的行为,若不希望如此,可以使用final关键字。
8.覆盖一个方法时,子类方法不能低于超类方法的可见性。即超类方法为public,子类方法必须也为public。
9.使用final关键字确保方法不被子类覆盖。final类的所有方法将被自动标记为final方法,但final类的字段并不会自动成为final字段。
10.使用instanceof操作符查看能否成功进行强制类型转换。例如:
if (staff[1] instanceof Manager)
{
boss = (Manager) staff[1];
// do something else...
}
if语句检测staff[1]是否可以成功强制类型转换为Manager类。
11.访问修饰符(权限越来越高)
12.使用@override注解来确定其下的是否为有效的覆盖重写。
13.子类方法返回值必须小于等于父类方法返回值。
1.静态代码块:用static 修饰的代码块
2.非静态代码块:没有static修饰的代码块
1.使用super关键字调用超类的构造器,语法如下:
public B(int a, double b, String s)
{
super(a, b, s);
int extra_var = 0;
}
使用super调用构造器的语句必须是子类构造器的第一条语句。
2.如果子类没有显示调用超类构造器,将自动调用超类的无参数构造器。
3.构造器的参数可以使用this传递给当前类的另一个构造器,也可以使用super传递给超类的构造器。
4.无论是this还是super,这一条语句必须是当前构造器的第一条语句。二者不可同时使用。
1.判断是否适合继承关系的原则——替换原则(“is-a规则”):子类的每个对象也是超类的对象,程序中出现超类对象的任何地方都可以使用子类对象替换。
2.在Java中,对象变量是多态的。可以将子类的对象赋给超类变量,即一个超类变量可以引用任何一个子类的对象。但反之,不能将超类的引用赋给子类的变量,因为这样可能会出现该子类变量无法调用子类特有的方法的现象。
尽管如此,编译器只将超类变量看做一个超类的对象,对其使用子类方法将产生错误。
3.在Java中,子类引用的数组可以不发生强制类型转换而直接转换成超类引用的数组,但它们实际上引用的是同一个数组,因此实际中要牢记初始数组的类型并避免发生类型转换。
4.在多态的代码当中,成员方法的访问规则是: 看new的是谁,就优先用谁,没有则向上找。
口诀:编译看左边,运行看右边。
对比一下:
1.使用abstract关键字表示超类中的某个方法无需实现而在子类中才被具体实现,包含一个或多个抽象方法的类本身必须被声明为抽象的。
2.不能用abstract修饰变量、代码块、构造器。
3.不能用abstract修饰私有方法、静态方法、final的方法、final的类。
4.抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提 供具体实现的对象的类。
1.编译器首先查看对象的声明类型和方法名,即编译器会列出子类所有名字与被调用方法名相同的方法和超类可访问的方法。
声明类型是指对象在声明时所指出的类型,对应的是实际类型,即被引用对象的实际类的类型。
2.然后,编译器要确定方法调用中提供的参数类型。
3.如果是static/ final/ private方法,则编译器可以准确知道应该调用哪种方法,称为静态绑定。
4.反之,若要调用的方法依赖于隐式参数的实际类型,则使用动态绑定。这时虚拟机必须调用与该对象变量所引用的对象的实际类型对应的那个方法,若没有,则在其超类中寻找该方法。
可以使用Object类型的变量引用任何类型的对象。
1.在子类定义equals方法时,应该首先调用超类的equals。
2.hashCode方法返回一个散列码,是由对象导出的一个整型值。
3.字符串的散列码是由内容导出的,而Object类默认的hashCode方法会从对象的存储地址得出散列码。
4.重新定义equals方法后,就需要重新对hashCode方法。
5.objectName.hashCode()方法返回一个散列码,而Object.hashCode(objectName)则先判断是否为null对象,是返回0,否则调用objectName.hashCode()方法。
6.如果equals方法返回true,则两个对象的hashCode方法也必须返回相同的散列码。
7.完备equals()方法建议:
1.toString方法会返回表示对象值的字符串。其中,可以使用getClass.getName()方法获得类名的字符串,这样子类也可以通过使用super.toString()获得超类部分对象值,在后面添加子类新增字段即可。
2.事实上,只要对象与一个字符串通过操作符“+”连接起来,Java编译器就会自动调用toString方法获得这个对象的字符串描述。
3.若想输出数组的内容,则需要调用静态方法Arrays.toString(arr)
1.声明语法:
ArrayList arr1 = new ArrayList<>();
ArrayList arr2 = new ArrayList();
var arr3 = new ArrayList();
建议使用var来避免重复写类名,不使用var时,右边尖括号中的类型可省略。
2.添加元素语法:
arr1.add(10);
arr2.add(new Integer(10));
arr1.add(1,100);
arr3.ensureCapacity(100);
ArrayList arr4 = new ArrayList(100);
完整添加语法为第二行,也可简写成第一行。第三行表示在索引1处添加值为10的元素,索引1表示位置1及之后的所有元素都要向后移动一个位置,把元素填入索引1这个位置上。
第三行使用ensureCapacity,这个方法将分配arr3一个包含100个对象的内部数组,这样前100次add操作就不会带来很大的开销来重新分配空间,也可使用第四行语句简单设置初始容量。
3.使用size()方法确定数组列表中包含的实际元素数量,大小确定后,可以使用trimToSize()方法将数组列表调整为当前元素容量大小。
4.访问元素语法:
arr1.get(index);
arr2.set(index, e);
使用get方法获得列表中下表为index(从0开始)的元素,使用set方法将元素e替换下标为index的元素。(添加请用add)
注意:这两种方法都需要数组列表大小大于index时才可以调用,否则会出现类似数组越界访问的错误。
5.使用toArray()方法将数组元素拷贝到一个数组中。
6.删除元素语法:
arr1.remove(0);
1.尖括号中的类型参数不允许是基本类型,需要使用基本类型转化而来的包装器类型。由于每个值都被分别包装在对象中,因此ArrayList
2.将基本类型转换为对象的类叫做对象包装器,如Integer,Double,Float等。
3.包装器类是不可变的,一旦构造便不可改变包装在其中的值。同时包装器是final类,不允许派生。
4.在ArrayList
5.==运算符可以用于对象包装器,但检测的是对象是否有相同的内存位置,对于[-128, 127)的short和int型数据来说,比较结果一定成功,否则不一定。
6.装箱和拆箱是编译器的工作,而非虚拟机。
1.将公共方法和字段放在超类中。
2.不要使用受保护的字段。
3.使用继承实现“is-a”关系。在使用继承前,考虑二者是否为包含关系,若不是,则慎重使用继承。
4.除非所有继承的方法都有意义,否则不要使用继承。
5.在覆盖方法时,不要改变预期的行为。
6.使用多态,而不要使用类型信息。
7.不要滥用反射。