Chapter05-继承

Evernote Export
一、关键字extends表明正在构造的新类诞生于一个已存在的类。
二、子类不能直接访问父类的私有域,应该通过super关键字和父类的访问器get方法访问。
三、java中父类对象变量可以引用父类对象也可以引用子类对象,称为 多态
四、如果是 private、static、final方法,编译器可以准确的知道调用哪个方法,称为 静态绑定动态绑定则是编译器需要 根据调用方法的对象的具体类型去判断调用哪个方法。动态绑定需要运行的时候搜索出匹配的方法,开销大,所以虚拟机为每个类都创建了一个用于查找的列出所有方法的签名和实际调用的方法的方法表。
五、有时候希望 阻止人们用某个类定义子类不允许扩展的类称为final类,如果杂定义类的时候使用了final修饰符就表明这个类是final。
六、有些程序员为了避免动态绑定带来的系统开销而使用final关键字。如果一个方法没有被覆盖并且很短,编译器就能对他进行优化处理,这个过程称为内联。
七、虚拟机中的即时编译器比传统编译器的处理能力强的多,可以准确知道类之间的继承关系,并能够检测出类中是否真正地存在覆盖给定的方法,如果方法简短被频繁调用,且没有被真正覆盖,那么即时编译器就可以进行内联处理。
八、将一个值存入变量,编译器将检查是否允许该操作。将一个子类的引用赋给一个超类变量,编译器是允许的,但将一个超类的引用赋给一个子类变量,必须进行类转换。养成一个良好的习惯,在进行类型转换之前,先查看一下是否能够成功转换。这个过程简单地使用 instanceof运算符就可以实现。
九、抽象方法充当占位的角色,具体实现在子类中,扩展抽象类可以有两种选择。一种是在子类中定义部分抽象方法或抽象方法也不定义,这样就必须将子类也标记为抽象类;另一种是定义全部的抽象方法,子类就不是抽象的了。
十、虽然抽象类不能实例化,但是可以定义抽象类的对象变量,但是引用非抽象子类的实例。
十一、如果希望超类的某些方法被子类访问,可将其设置为protected,但是要谨慎,因为子类可以通过protected方法访问一些受保护的域。

十二、由多态,父类变量可以引用父类或子类对象,所以 Object类型的变量可以引用任何类型的对象,Object类的equals方法用于检测一个对象是否等于另一个对象,判断两个对象是否具有相同的引用。getClass方法将返回一个对象所属的类。在子类中定义 equals方法时,首先调用超类的equals。
从两种方法看相等测试的问题:1.如果子类能够拥有自己的相等概念,则对称性需求将强制采用getClass进行检测。2.如果由超累决定相等的概念,就可以使用instanceof进行检测,这样可以在不同子类的队形之间进行相等的比较。
下面是一个编写比较完美的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的语义在每个子类中有所改变,就是用getClasss检测
if(getClass()!=otherObject.getClass())return false;
如果所有的子类都拥有统一的语义,就使用instanceof检测:if(!(otherObjcet instanceof ClassName))return false;
5)将otherObject转换为相应的类类型变量
ClassName other=(ClassName)otherObject
6)现在开始对所有需要比较的域进行比较。使用==比较基本类型域,使用equals比较对象域,如果所有的域都匹配,就返回true,否则返回false。
return field1==other.field1
    &&field2.equals(other.field2)
        &&...;
如果在子类中重新定义equals,就i要在其中包含调用super.equals(other)。
从Java SE5.0开始为了避免发生类型错误,可以使用@Override对覆盖超累的方法进行标记。如果出现错误,并且正在定义一个新方法,编译器就会给出错误报告。

API(java.util.Arrays)
static Boolean equals(type[] a,type[] b)如果两个数组长度相同,位置上数据元素也均相同,将返回true。

十三、 hasCode方法定义在Object类,因此每个对象都有一个默认的散列码,其值为对象的存储地址。如果重新定义equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中。HashCode方法应该返回一个整型数值,并合理地组合实例域的散列码,以便能够让各个不同的对象产生的散列码更加均匀。Equals与hashCode的定义必须一致:如果x.equals(y)返回true,那么x.hasCode()就必须与y.hashCode()具有相同的值。

API(java.lang.Object)
int hashCode()//返回对象的散列码,散列码可以是任意的整数,包括正数或负数,两个相等的对象要求返回相等的散列码。
API(java.util.Arrays)
static int hashCode(type[] a)//计算数组a的散列码,组成这个数组的元素类型可以是object,int,long,short,char,byte,boolean,float或double

十四、Object中的重要方法 toString方法,返回表示对象值的字符串,绝大所属的toString方法都遵循这样的格式:类的名字,随后是一对方括号括起来的域值。还可以设计的更好,通过调用getClass().getName()获得类名的字符串,而不要及那个类名硬加到toString。随处可见toString方法的主要原因是:只要对象与一个字符串通过操作符“+”连接起来,Java编译器就会自动的调用toString方法,以便获得这个对象的字符串描述。数组继承了object类的toString方法,将按照旧的格式打印,可以使用修正的方式是调用静态方法Arrays.toString.

API(java.lang.Object)
Class getClass()//返回包含对象信息的类对象,稍后会考到Java提供了类运行时的描述
boolean equals(Object otherObject)//比较两个对象是否相等,如果两个对象指向同一块存储区域,方法返回true,否则方法返回false。在自定义的类中应该覆盖该方法
String toString()
Object clone()//创建一个对象的副本,Java运行时系统将为新实例分配存储空间,并将当前的对象复制到这块存储区域中

十五、一旦确定了数组的大小,改变他就不太容易了,在Java中解决这个问题最简单的方法是使用Java中另一个被称为 ArrayList的类。它使用起来像数组,但在添加或删除元素时,具有自动调节数组容量的功能,而不需要为此编写任何代码。在Java SE中ArrayList是一个采用类型参数的泛型类,为了指定数组列表保存的元素对象类型,需要用一对尖括号将类名括起来加在后面。如果已经清楚或能够估计数组可能存储的元素数量,就可以在填充数组之前嗲用ensureCapacity方法。一旦能够确认数组列表的大小不再法僧变化,就可以调用trimToSize方法。这个方法将存储区域的大小调整为当前元素数量所需要的存储孔吉纳数目,垃圾回收器将回收多余的存储空间。
API(java.util.ArrayList<T>)
ArrayList<T>()//构造一个空数组列表
ArrayList<T>(int initialCapacity)//用指定容量构造一个空数组列表
boolean add(T obj)//在数组尾端添加一个元素
int size()//返回当前元素数量
void ensureCapacity(int capacity)//确保数组列表在不重新分配存储空间的情况下就能够保存给定数量的元素
void trimToSize()
void set(int index,T obj);
T get(int index)
void add(int index,T obj)
T remove(int index)

十六、所有基本类型都有一个与之对应的类,叫包装器,对象包装器是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。对象包装器类还是final,依次不能定义他们的子类。要想将字符串转换成整型,可以使用下面这条语句
int x = Integer.parseInt(s);
parseInt是一个静态方法。包含在包装器中的内容不会改变,不能使用给这些包装器类创建修改数值参数的方法。如果想编写一个修改数值参数值的方法,就许哟使用在org.omg.CORBA包中定义的持有者类型

API(java.lang.Integer)
int intValue()//以int形式返回Integer对象的值
static String toString(int i)//以一个新String对象的形式返回给定数值i的十进制表示
staitc String toString(int i,int radix)//返回数值i的基于给定raidx参数进制的表示
static int parseInt(String s)//返回字符串s表示的整形数值,给定字符串表示的十进制的整数,或者是radix参数进制的整数
static int parseInt(String s,int radix)
static Integer valueOf(String s)
Static Integer valueOf(String s,int radix)
API(java.text.NumberFormat)
Number parse(String s)//假定给定的String表示了一个数值,返回数字值

十七、可以自己定义可变参数的方法,并将参数指定为任意类型,甚至基本类型。

十八、所有的枚举类型都是Enum类的子类。他们继承了这个类的许多方法,其中最有用的一个toString,这个方法能够返回枚举常量名。每个枚举类型都有一个静态的values方法,他将返回一个抱哈全部枚举值的数值,ordinal方法返回enum声明中枚举常量的位置,从0开始计数。

API(java.lang.Enum)
static Enum valueOf(Class enumClass,String name)//返回指定名字,给定类的枚举常量
String toString()
int ordinal()
int compareTo()//如果枚举常量出现在other之前,则返回一个负值,如果this==other,则返回0,否则,返回正值

十九、在程序运行期间,Java运行时系统时钟为所有的对象维护一个被称为运行时的类型标志,这个信息保存着每个对象所属的类足迹。虚拟机利用运行时信息选择相应的方法执行。可以通过专门的Java类访问这些信息,保存他们的类叫Class,这个名字很容易让人混淆,Object类中的getClass()方法将会返回一个Class类型的实例。最常见的Class方法是getName,返回类的名字。还可以调用静态方法forName获得类名对应的Class对象。这个方法只有在className是类名或是接口名时才能够执行。否则,forName方法将抛出一个checked exception。虚拟机为每个类型管理一个Class对象,因此可以利用==运算符实现两个类对象比较的操作。newInstance()方法,而已用来快速地创建一个类的实例。将forName与newInstance配合起来使用,可以根据存储在字符串中的类名创建一个对象。

API(java.lang.Class)
static Class forName(String className)//返回描述类名为className的Class对象
Object newInstance()//返回这个类的一个新实例
API(java.lang.reflect.Constructor)
Object newInstance(Object[] args)//构造这个构造器所属类的新实例
API(java.lang.Throwable)
void printStackTrace()//将Throwable对象和栈的轨迹输出到标准错误流

二十、在java.lang.reflect包中有三个类Field、Method、Constructor分别用于描述类的域、方法和构造器。这三个类都有一个getName的方法,用来返回项目的名称。Field类有一个getType方法,用来返回描述域所属类型的Class对象。Method和Constructor有能够报告参数类型的方法,这三个类还有一个叫做getModifiers的方法,它将返回一个整型数组,用不同位开关描述public和static这样的修饰符使用状况。另外还有java.lang.reflect包中的Modifier类的静态方法分析getModifier返回的整型数值。例如,可以使用Modifier类中isPublic、isPrivate或isFinal判断方法或构造器是否是public ,private或final。还可以利用Modifier.toString方法将修饰符打印出来。Class类中的getFields、getMethods和getConstructors方法将返回蹄冻的public域、方法、构造器数组。其中包括超累的公有成员。Class类的getDeclareFields、getDeclareMethods和getDeclaredConstructor方法将分别返回类中声明的全部域、方法、构造器,包括私有和受保护成员,不包括超累成员。

API(java.lang.class)
Field[] getFields()
Field[] getDeclareFields()//返回包含Field对象的数组,这些对象记录了这个类或其超累的公有域。getDeclareFields则返回包含Field对象的数组,这些对象记录了这个类的全部域
Method[] getMethods()
Method[] getDeclareMethods()//返回包含Method对象的数组,getMethods将返回所有的公有方法,包括从超类中继承来的,getDeclaredMethods则返回这个类或接口的全部方法,但不包括超类继承的
Constructor[] getConstructor()
Constructor[] getDeclaredConstructors()//返回包含Constructor对象的数组,包含了Class对象所描述的类的所有公有构造器或所有构造器
API(java.lang.reflect.Field)(java.lang.reflect.Method)(java.lang.reflect.Constructor)
Class getDeclaringClass()//返回一个用于描述类中定义的构造器、方法或域的Class对象
Class[] getExceptionTypes()//返回一个用于描述方法抛出的异常类型的Class对象数组
int getModifiers()//返回一个用于描述构造器、方法或域的修饰符的整型数组
String getName()//返回一个用于描述构造器、方法或域的字符串
Class[] getParameterTypes()//返回一个用于描述参数类型的class对象数组
Class getReturnType()//返回一个用于描述返回类型的Class对象。
API(java.lang.reflect.Modifier)
static String toString(int Modifiers)//返回对应modifiers位设置的修饰符的字符串表示
static boolean isAbstract(int Modifiers)
static boolean isFinal(int modifiers)
static boolean isInterface(int modifiers)
static boolean isNative(int modifiers)
static boolean isPrivate(int modifiers)
static boolean isProtected(int modifiers)
static boolena isPublic(int modifiers)
static boolean isStatic(int modifiers)
static boolean isStrict(int modifiers)
static boolean isSynchronized(int modifiers)
static boolean isVolatile(int modifiers)

二十一、查看对象域的关键方法是Field类中的get方法。如果f是一个Field类型的对象,obj是某个包含f域的类的对象,f.get(obj)将返回一个对象,其值为obj域的当前值,但是如果访问的域是私有域,get方法会抛出一个IllegalAccessException。除非拥有访问权限,否则Java安全机制只允许查看任意对象有哪些域,不允许读值。反射机制默认行为受限于java的访问控制,如果一个Java程序员没有收到安全管理器的控制,就可以覆盖访问控制,为了达到这个目的,需要调用Field、Method或Constructor对象的setAccessible方法。setAccessible方法是AccessibleObject类中的一个方法,是Field、Method、Constructor的公共超类。是为调试,持久存储和相似机制体提供的。

API(java.lang.reflect.AccessibleObject)
void setAccessible(boolean flag)//为反射对象设置可访问标志,flag为true表明屏蔽Java语言的访问检查,使得对象的私有属性也可以被查询和设置
boolean isAccessible()//返回反射对象的可访问标志的值
static void setAccessible(AccessibleObject[] array,boolean flag)//是一种设置对象数组可访问标志的快捷方法。
API(java.lang.Class)
Field getField(String name)
Field[] getField()//返回指定名称的公有域,或包含所有域的数组
Field getDeclaredField(String name)
Field[] getDeclaredFields()//返回类中声明的给定名称的域,或者包含声明的全部域的数组
API(java.lang.reflect)
Object get(Object obj)//返回obj对象中用Field对象表示的域值
void set(Object obj,Object newValue)//用newVlaue设置obj对象中用Field对象表示的域

二十二、使用反射编写泛型数组代码。为了编写这类通用的数组diamagnetic,需要能够创建与原数组类型相同的新数组,为此,需要java.lang.reflect包中Array类的一些方法,其中个最关键的是Array类中静态方法newInstance,他能构造新数组。调用时必须提供两个参数,一个是数组的元素类型,一个是数组的长度。
Object newArray= Array.newInstacnec(componentType,newLength);

API(java.lang.reflect.Array)
static Object get(Object array,int index)
static xxx getXxx(Object array,int index)//返回存储在数组上给定位置的内容
static void set(Object array,int index,Object newValue)
static setXxx(Object array,int index,xxx newValue)//将一个新的值存储在给定数组的位置上
static int getLength(Object array)
static Object newInstance(Class componentType,int length)
static Object newInstance(Class componentType,int[] lengths)//返回一个具有给定类型和给定维数的新数组

二十三、在Method类中有一个 invoke方法,他 允许调用包装在Method对象中的方法。invoke方法的签名是:Object invoke(Object obj,Object...args)。第一个参数是隐式参数,其余的对象提供显示参数,对于静态方法,第一个参数可以忽略,将他设置为null。如果返回类类型是一种基本类型,则 invoke方法将返回包装器类型。因此必须相应的进行类型转换。如何得到Method对象呢,可以调用getDeclareMethods方法,然后对返回Method对象数组进行查找,也可以通过Class类中的getMethod方法得到想要的方法。

猜你喜欢

转载自blog.csdn.net/Han_L/article/details/88049939
今日推荐