java核心技术基础知识

java核心技术基础知识个人总结之——继承和反射
一、类、子类、超类:
1、用extends表示子类继承超类的关系,超类中的私有域在子类中一样不能通过子类去调用,只有通过超类的方法才能够访问超类私有的部分,可以用super.method()调用超类的方法,但是这里的super不是一个对象的引用,它只是一个指示编译器调用超类方法的特有关键字。
2、使用super调用超类构造器的语句必须是子类构造器的第一条语句。如果子类构造器没有显式地调用超类的构造器,则将自动地调用超类默认构造器,如果超类没有不带参数的构造器,并且在子类的构造器中又没有显式地调用超类的其他构造器,则java编译器将报错。学到这,不自然的让我想到一种结构:内部类。个人觉得可以把继承的关系看做是在子类中有了一个超类的内部类对象并进行了安全的构造初始化,所有可以在必要的时候用super.method()去访问该对象里的公用方法(一般情况下是直接用方法名调用方法),如果子类覆盖了超类的方法,那么外部调用的时候,解释器会去先找子类方法从而屏蔽了超类对象的方法,这样理解只是方便理解,但是事实肯定不是这样的。
3、一个对象变量可以引用对种实际类型的现象被叫做多态,对象变量遵行置换法则:超类对象的任何地方都可以用子类对象置换,但是声明为类型为超类对象的变量就算引用了一个子类的对象,用该引用还是不能调用子类特有的方法,因为"超类不是子类",而"子类肯定超类"。在运行时能够自动地选择调用哪个方法的现象叫做动态绑定,调用方法依赖于隐式参数的实际类型,在JAVA5以前的版本中,要求覆盖方法的返回类型必须是一样的,而现在允许子类将覆盖方法的返回类型定义为原返回类型的子类型。
4、继承关系程度比较多的话,动态绑定调用方法的过程是:如果子类定义了该方法则调用,否则在父类中需找,没有继续类往上找。(为了节约开销,虚拟机会预先为每个类创建一个方法表,调用方法时先按顺序搜索方法表)。子类覆盖超类的一个方法的时候,子类方法不能低于超类方法的可见性。
以上内容的例子:
class MyParentClassA{
private String str;
public MyParentClassA(String s){
str=s;
}
public String getStr(){
return str;
}

}
class MyParentClassB{
public MyParentClassB(String s){
super(s);
}

}
public class SuperClassTest extends MyParentClassB{
private String str;
public SuperClassTest(String s){
super(s);
str="this is child";
}
public String getStr(){
return super.getStr()+" "+str;
}
public void methodTochild(){

}
public static void main(String args[]){
MyParentClassA[]

mpcArray=new MyParentClassA[2];
mpcArray[0]=new MyParentClassA("parent");
mpcArray[1]=new SuperClassTest("parent's child");
for (MyParentClass m:mpcArray){
System.out.println(m.getStr());
}
mpcArray[0].methodTochild();//error: parent is not a child
}
}
需要注意的是:
SuperClassTest []test=new SuperClassTest [2];
MyParentClass []mpc=test;
这样做可以通过编译,SuperClassTest 是一个MyParentClass ,但是当mpc[0]=new MyParentClass();此时test[0]和mpc[0]引用同一个对象,当调用test[0].methodTochild()
会导致调用一个不存在的实例域,从而打乱了相邻存储空间的内容,所以在mpc[0]=new MyParentClass()时就会抛出:https://www.360docs.net/doc/164078052.html,ng.ArrayStoreException,不允许放入子类的引用。

5、final 类:用来阻止继承。final类中的所有方法自动变为final的,但是类的域不会。类被声明为final就不能被继承,方法声明为final就不能被覆盖。在设计类层次的时候应该仔细考虑哪些方法和类声明为final。

6、强制类型转型:如果在继承链上进行向下的强制转型,并且本来就不是向下的类型,这个时候会产生ClassCastException异常。所以在进行类型转型之前,先要检查一下是否能够转型成功:o instanceof Object,如果x为null,不会产生异常,只会返回false,因为null没有引用任何对象。注意当需要强制转型的时候应该坚持下类是否设计的合理,是否真的需要用超类的引用去调用子类的方法。

7、抽象类:包含一个抽象方法的类本身必须声明为抽象类。其实抽象方法充当着占位的角色,这样子类实现该方法,用抽象父类的引用可以统一调用占位的方法。



二、Object:所有类的超类
1、equals,用于检测一个对象是否等于另外一个对象,可以重载,String就重载了它,只要内容相同就返回true,当我们重载equals时需要注意以下几点:
自反性 :对任意引用值X,x.equals(x)的返回值一定为true.
对称性: 对于任何引用值x,y,当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;注意如果equals的语义在每个子类中有所改变,就要用getClass检测
传递性:如果x.equals(y)=true, y.equals(z)=true,则x.equals(z)=true
一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变
非空性:任何非空的引用值X,x.equals(null)的返回值一定为false
覆盖Object的equals方法参数一定是Object类型的。

2、HashCode方法:用同样的内容构造的String 和StringBuilder的HashCode是不同的,因为StringBuilder类中没有定义hashCode方法,他的散列码是由Object的默认方法导出的对象存储地址(所有没有覆盖HashCode方法的类导出的都是这个)。
Arrays类有静态方法hashCode(type[] a),这个散列码

由数组元素的散列码组成。
注意:equals与hashCode的定义必须一致,如果equals方法返回true,那么hashCode就必须相同,所以hashCode需要散列的东西要来自equals方法里要比较的域。

3、toString:大部分的类的toString方法遵循这样的格式:类的名子,随后是一对方括号括起来的值域。
数组类型按照旧格式打印:[类型第一个字符@地址,所以我们想知道数组的内容要调用Arrays的静态方法toString(type[]),多维数组调用Arrays.deepToString(type[])。
建议为自定义的每一个类都添加一个toString方法。

Object主要有以上3个重要方法,还有的就是clone()和getClass。可以注意到,Arrays类里都有以上3个静态方法,所以我们要用数组调用的以上3个方法时要用Arrays的静态类。


三、泛型数组列表:ArrayList 构造方法接受一个int,用来设置初始容量,也可以用对象调用ensureCapacity(int i)来设置初始容量,一旦能够确认数组列表的大小不再发生变化,可以调用trimToSize方法,这个方法将存储区域的大小调整为当前元素数量所需要的存储空间数目,垃圾回收器将回收多余的存储空间。
add(Object o):添加元素添加到最后,add(int i,Object o)在i位置插入一个新元素;remove(int i)删除i位置的元素;size():返回当前元素数量;set(int i,Object o)设置第i个元素,get(int i)得到到第i个元素;toArray返回一个包还所有元素的数组。可以使用for each语法。



四、基本类型的包装器与自动打包:从公共超类Number派生出来的有:Byte Short Integer Long Float Double;其他的还有:Character Void Boolean。对象包装器类都是final的,不能定义他们的子类,而且一旦构造了包装器,就不允许更改包装在其中的值。泛型要用基本类型都要用包装器。
自动打包是指在需要int的地方,编译器会自动的添加必要的方法调用,自动让他们变为int后又自动封装回去。
包装器可以提供很多有用的方法(以Integer为例,其他的类似):
1、int intValue()返回Integer对象的值
2、Static toString(int i) ||toString(int i,int num)返回指定数值i的串,第2种协变参数的num指定进制。
3、Static int parseInt(String s) ||toString(String s,int num) 返回字符串s表示的整型数值,第2种协变参数的num指定进制。
4、Static Integer valueOf(String s) ||toString(String s,int num) 返回字符串s表示的整型数值进行初始化后的Integer对象,第2种协变参数的num指定进制。


五、参数数量可变的方法:callMethod(type... args)表明可以接受任意数量的对象,其实编译器将其打包成了数组。



六、反射:能够分析类能力的程序被称为反射。java运行时系统始终为所有的对象维护一个被称为运行时的

类型标示,这个信息保存着每个对象所属的类足迹。
1、class类:用来保存对象运行时的信息,得到该对象的方法有:a、Object类中的getClass()方法返回一个Class类型的实例。b、Static forName(String classname):通过类名获得一个对应的Class对象。c、用 类名.class 代表对应的Class对象。一个class对象实际上表示的一个类型,而这个类型未必是一种类,例如可以:int.class。

class类里的一般的方法有:getName()返回类的名子。如果类在一个包里,那么包名也会作为类名的一部分。
newInstance():可以用来快速地创建一个类的实例 ,调用的是默认的构造器,如果这个类没有默认的构造起就会抛出一个异常。

2、利用反射分析类的能力:Class类中的getFields(),getMethods(),getConstructors()这三个方法分别返回对应类的field(封装域信息),method(封装方法信息),constructor(封装构造器信息)对象的数组(都是public的域,方法或则构造器),getMethods()返回的是所有的公有方法,包括从超类继承来的方法。
getDeclareMethod()返回这个类的全部方法包括该类的私有方法,但不包括由超类继承了的方法。
getDeclareField()返回的是这个类的所有域,但不包括由超类继承了的方法。
getDeclareConstructor()返回的是所有的构造器。

Field、Method、Constructor类都有的方法:String getName()返回该域的名字;int getModifiers()返回一个整形数值用来描述成员的修饰符,Modifier类有很多静态方法可以对这个整型做判断,比如isPublic等;Class getDeclaringClass()返回一个用于描述定义的构造器、方法或者域的Class对象。

field类:Class getType()方法返回描述域所属类型的Class对象。Object get(Object o)方法的参数是某个包含域F的类的对象,返回该对象的这个域的原始对象,对于基本类型有相应的getInt等。注意的是如果没有调用setAccessible(true)(这个方法并不是永远的能有效的,在一些服务器比如weblogic,可以通过安全性设置来屏蔽这个函数的功能),只能得到可访问(public)的域的值。(很明显,通过这个机制,多少破坏了封装性)

Method类:Class[] getParameterTypes()返回描述该方法参数类型的Class数组。 Class getReturnType()返回描述该方法返回值类型的Class对象。Class[] getExceptionTypes返回描述该构造器方法抛出异常类型的Class对象数组。

Constructor类:Class[] getParameterTypes()返回描述该构造器方法参数类型的Class数组。Class[] getExceptionTypes返回描述该构造器方法抛出异常类型的Class对象数组。


3、使用反射里的数组:Class类里的有getComponentType方法确定数组对应的类型。
Array:Static Object newInstance(Class cl,int length)可以通过CL类型创建一个长度为lengt

h的数组。
Static Object get(Array a,int index)通过索引返回数组A指定位置的对象。基本类型就是相应的get方法,如:getInt(Array a,int index);
statci int getLength(Object o)返回数组o的长度。

4、方法指针:Method类 : Object invoke(Object,Object...args)方法第一个参数是隐式参数(要在哪个对象上调用,如果是静态方法,其可以为null),其余的对象提供的是显式参数,如果没有就传一个null,如果方法返回的是基本类型,那么调用invoke可以返回基本类型的包装类。
Method getMethod(String s,Class...parameterTypes) :提供了参数的类型信息,可以在很多重载的方法中返回准确的对象。


七、继承设计的技巧:1、将公共操作和域放在超类。2、最好不要使用protected域。3、明确“是一个”的继承关系。4、除非所有的继承方法都有意义,否则最好不要使用继承。
5、在覆盖方法的时候,不要改变预期的行为。6、多使用多态,而不是类型信息。7、不要过多的使用反射。

相关文档
最新文档