继承
-
“is-a”关系是继承的一个明显特征
-
定义子类继承用extends
-
子类定义的新方法,声明为超类的对象不能使用
-
子类方法通过使用超类方法(公有接口)访问超类的私有域
super.getsalary();
-
子类只能增加或者覆盖超类的方法,但是不能删除继承的任何域或者方法
-
由于子类不能直接访问超类的私有域,因此子类的构造器需要利用超类的构造器对这部分不能直接访问的私有域进行初始化
super(name,salary,year,month,day);
-
一个对象变量可以指示多种实际类型的现象称为多态(polymorphic),在运行时能够自动地选择调用哪个方法的现象称为动态绑定(dynamic binding);由private、static、final等修饰的方法,调用时为静态绑定
-
由超类派生出来的所有类的集合称为继承层次
-
置换法则:程序中出现超类对象的任何地方都可以用子类对象置换;超类不能赋给子类
-
忌讳发生将子类数组的引用赋给父类数组,每个数组都要牢记创建它们的元素类型,只能调用这个元素类型下的方法,防止导致调用不存在的实用域
-
为了节约调用方法的时间开销,虚拟机预先为每个类创建了一个方法表(method table),P156的例子
-
动态绑定有一个特性:无须对现存的代码进行修改,就可以对程序进行拓展
-
阻止继承:final修饰的方法和类;不允许拓展的类被称为final类,final类的所有方法自动地成为final方法,对于final域来说,构造对象后就不允许改变它们的值
-
如果将一个类声明为final,只有方法自动成为final,但是不包括实例域
-
超类转换成子类之前,即强制类型转换前,先习惯使用
if(staff[1] instanceof Manager){}
判断能否转换成功 -
只能在继承层次(所有派生类的集合)内进行类型转换
-
一般情况下尽量少使用instanceof,尽量少使用强制类型转换
-
抽象类用于设置更具有普适性的属性,使用abstract关键字,包含一个或多个抽象方法的类本身必须被声明为抽象
public abstract class person { ... public abstract String getDescription(); }
-
抽象类充当着占位的角色,声明在抽象类中,具体实现在子类中,当调用这个方法时,必须是由抽象类声明的对象才能调用,即编译器只允许调用在类中声明的方法
-
抽象类不能实例化,类似C++中在尾部=标记0的抽象方法成为纯虚函数
-
在子类中具体实现抽象方法时,不用加abstract
-
最好将类中的域标记为private,方法标记为public
-
子类可以访问超类被声明为protected的域
-
1)仅对本类可见——private
2)对所有类可见——public
3)对本包和所有子类可见——protected
4)对本包可见——默认(很遗憾),不需要修饰符 -
Object是Java所有类的始祖(根类),没有明确指出超类,则Object就被认为是这个类的超类
-
除了基本类型,例如数值、字符和布尔类型外,其他类型都是对象,因此都扩展了Object类,因此
Object obj = new int[10];
-
编写一个完美的 equals 建议:
1)显示参数命名为otherObject,稍微需要将它转换成另一个叫做other的变量
2)检测this与otherObject是否引用同一个对象:if(this==otherObject) return true;
3)检测otherObject是否为null,如果为null,返回false:if(otherObject == null) return false;
4)比较this与otherObject是否同属一个类,如果equals的语义在某个子类中有所改变,就是用getClass检测:
if(getClss()!=otherObject.getClass()) return false;
如果所有的子类都拥有统一的语义,就是用instanceof检测:
if(!(otherObject instanceof ClassName)) return false;//ClassName为比较的类名
5)将otherObject转换为相应的类类型变量:
ClassName other = (ClassName) otherObject;
6)现在开始对所有需要比较的域进行比较。使用==比较基本类型域,使用equals比较对象域,&&
7)如果在子类中重新调用equals,就要在其中包含调用super.equals(other),如果超类中的域都相等,再需要比较子类中的域 -
数组可以使用静态的Array.equals方法检测数组元素是否相等
-
为了防止覆盖方法时,由于类型错误,而定义一个与超类无关的方法,使用@Override对覆盖超类的方法进行标记
-
散列码(hase code)是由对象导出的一个整型值,没有规律
-
Object类中由hashCode方法,由此得到的散列码是每个对象的默认值,即存储地址,除非类覆盖了hashcode方法
-
如果重新定义了equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表
-
Object.hashCode 是null安全的方法,会检查null,返回0
-
当需要组合多个散列值时,可以调用Object.hash并提供多个参数
-
equals和hashCode的定义必须一致,如果equals返回为true,那么比较的两者的散列码也必须一致
-
绝大多数的(但不是全部)toString方法都遵循这样的格式:类的名字,随后是一对方括号起来的域值。toString用于返回表示对象值的字符串
-
如果父类定义了getClass().getName(),子类定义自己的toString方法时,添加自己的子类域,可以调用super.toSring(),然后再后面+“子类域”
-
在调用x.toString()的地方可以用 “”+x 替代。这条语句将一个空串与x的字符串表示相连接,这里的x就是x.toString()。与toString不同的是,这里x可以是基本类型。
-
println自动调用x.toString(),并打印输出得到的字符串
-
Object类也定义了toString方法,用来打印 类名 + 散列码
-
输出数组需要借助Arrays.toString(a)
-
java.lang.Object 类是java语言中的根类,所有类的父类; Objects类是jdk1.7后出现.提供静态方法来操作对象
-
泛型数组列表,ArrayList是一个采用类型参数的泛型类,类似C++中的vector
-
使用add方法将元素添加到数组列表中,当调用add且内部数组已经满了,数组列表将自动创建一个更大的数组,如果已经清楚或能够估计出数组可能存储的元素数量,就开业在填充前调用ensureCapacity:
staff.ensureCapacity(100);
或者把初始容量传递给ArrayList构造器:ArrayList<Employee> staff = new ArrayList<>(100);
-
ArrayList<Employee> staff = new ArrayList<>(100);
数组列表的这种分配方式只是拥有了保存100个元素的潜力,不含有任何元素(size和capacity不一样),一旦确定数组列表的大小不再发生变化,就调用trimToSize方法,将存储区域的大小调整为当前元素数量所需要的存储空间数目,多余被回收 -
ArrayList使用size()代替length计算元素的数目
-
对象包装器是不可变的,即构造了包装器后,其内容是不能再更改的了,基本数据类型的数组列表的尖括号内不能是基本类型,需要使用基本类型的包装器
-
包装器有很有用的特性就是自动装箱和自动拆箱,方便将基本类型(int等)添加到数组列表中
-
对象包装器也可以使用==进行比较,但是检测的是对象是否指向同一个存储区域
-
如果在一个条件表达式中混用Integer和Double类型,Integer拆箱后会被提升到Double
Integer n = 1; Double x = 2.0; System.out.println(true ? n :x);//Prints 1.0
-
如果想要编写一个修改数组参数值的方法,需要使用持有者(holder)类型,每个持有者类型都包含一个公有域值,通过它可以访问存储在其中的值
public static void triple(IntHolder x) { x.value = 3 * x.value; }
-
参数可变的方法是在参数列表中使用 … ,这是java代码的一部分,表明这个方法可以接受任意数量的对象
(Object... args)
-
用户自定义可变参数的方法
public static double max(double... values) { double largest = Double.NEGATIVE_INFINITY; for(double v : values) if(v > largest) largest = v; return largest; }
调用
double m = max(3.1,40.4,-5);
编译器将new double[]{3.1,40.4,-5}传递给max方法 -
比较两个枚举类型的值时,永远不需要调用equals,直接调用“==”
-
所有枚举类型都是Enum的子类,可以调用这个类的许多方法,toString可以返回枚举常量名,valueOf是toString的逆方法
Size s = Enum.valueOf(Size.class,"SMALL");//即设置枚举值
-
不要过多使用反射,反射机制通过在运行时查看域和方法