Java继承,接口与内部类

子类对象的方法不能直接访问超类的私有域,尽管每个子类对象都拥有这个私有域,但是在子类的方法中却不能直接访问这个域。只有超类的方法才能够访问私有部分。如果子类一定要访问父类私有域,就必须借助共有的接口。调用超类的方法,如果这个方法在子类中也有,那就必须用super。子类用可以增加自己的部分,覆盖超类的部分方法,但是绝对不能删除继承的任何域和方法。

 

使用super调用超类构造器的语句必须是子类构造器的第一局话。如果子类的构造器没有现实的调用超类的构造器,那么系统自动的调用超类默认的构造器,就是没有参数的那个构造器,如果超类没有不带参数的构造器,并且在子类的构造器中又没有显示的调用超类的其他构造器,那么编译器就会提示错误。

 

一个对象变量可以引用多种实际类型的现象被称为多态,在运行时能够自动的选择调用哪个方法的现象叫做动态绑定。方法的名字和参数列表成为方法的签名,不过返回类型不是签名的一部分,在覆盖方法的时候,一定要保证返回类型的兼容性。现在允许子类将覆盖方法的返回类型定义为原返回类型的子类型。

 

在覆盖一个方法的时候,子类方法不能低于超类方法的可见性。特别是父类方法是public,那么子类方法一定要声明为public。

 

阻止继承要用 final类和方法。域也可以声明为final,对于final域来说,构造对象之后就不允许改变他们的值了。不过如果将类声明为final,只有其中的方法自动的成为final,而不包括域。

 

抽象类

public abstract String getDescription();加上abstract就不需要实现这个方法了,包含一个或多个抽象方法的类本身必须声明为抽象的。抽象方法起着占位的作用,他们的具体实现在子类中。扩展抽象类有两种选择,1 在子类中定义部分抽象方法或者抽象方法也不定义,这样就必须把子类也定义为抽象类,2,是定义全部抽象方法,这样一来子类就不是抽象的了。类即使不含抽象方法,也可以将类声明为抽象类。除了抽象方法外,抽象类还可以包含具体数据和具体方法。抽象类不能被实例化。但是可以定义一个抽象类对象,不过他只能引用它的非抽象子类的对象。由于不能构造抽象类的对象,所以抽象类变量引用的永远不是抽象类对象,而是引用的一个非抽象子类的对象,而在这些对象里面的方法一定都是具体的了。

 

归纳一下JAVA用于控制可见性的4个访问修饰符

private 只对本类可见

protect 对本包和所有子类可见

默认是对本包可见

public 对所有类可见。

 

Equals方法

在子类中定义equals方法是,首先调用超类的equals方法,如果检测失败,对象就不可能相等,如果超类中的域都相等,然后就需要比较子类中的实例域。

如果子类能够拥有自己的相等的概念,则对称性需求将强制采用getClass进行检测。

如果超类决定相等的概念,那么就可以使用instanceof进行检测,这样可以在不同子类的对象之间进行相等的比较。

编写完美的equals方法的建议

1. 显式参数命名为otherObject,稍后需要将它转换成另一个叫做other的变量。

2.检测this与ohterObject是否引用同一对象,if(this==otherObject) return TRUE; 这条语句只是一个优化,实际上,这是一种经常采用的形式,因为计算这个等式要比一个一个的比较类中的域要付出的代价小得多。

3.检测otherObject是否为null,如果为null,返回FALSE,这项检测是很必要的。 if(otherObject==null) return FALSE

4.检测this与otherobject是否属于同一类,如果equals得语义在每个子类中有所改变,就用getcLASS检测, if(getClass()!=otherobjec.getClass()) return false

如果所有的子类都拥有同一的语义,就是用InstanceOf 检测,if(!(otherObject instanceOf ClassName)) return false

5.将otherObject转换为相应的类类型变量, ClassName other = (ClassName)otherObject

6.现在开始对所有需要比较的域进行比较。使用==比较基本类型域,使用equals比较对象域,如果所有的域都匹配,就返回TRUE,否则就FALSE

如果在子类中重新定义equals就要在其中包含调用super.equals(other)

对于数组类型的域,可以使用静态的Arrays.equals方法检测相应的数组元素是否相等。

 

hashCode方法定义在object中,因此每个对象都有一个默认的散列吗,其值为对象的储存地址。

如果重新定义equals方法,就必须重新定义hashcode方法,以便用户可以将对象插入到散列列表中。equals必须和hashcode定义一致,如果equals返回TRUE,那么那么两个对象的hashcode就必须具有相同的值。如果存在数组类型的域,就可以使用静态的arrays.hascode方法计算一个散列吗,这个散列码有数组元素的散列吗组成。

 

Object的equals方法是比较两个对象是否相等,如果两个对象指向同一块存储区域,方法返回TRUE,否则方法返回FALSE,在自定义类中应该覆盖这个方法

object的clone方法是创建一个对象的副本,为新实例分配存储空间,并将当前的对象复制到这个存储区域中区。

 

对象包装器类是不可变的,即一旦构造了包装器,就不允许改变其中的值。而且还是final类,不允许有子类。

 

可变参数数量

double max(double... values) double...参数类型与object[]完全一样。可以接受任意数量的参数,这里把values堪称数组,调用时吧参数打包进数组。

枚举类
public enum Size {SMALL, LARGE, MEDIUM, EXTRA_LARGE}比较两个枚举类型的值时,不要用equals,直接用==

toString的逆方法是静态方法valueOf,比如Size s = (Size) Enum.valueOf(Size.class, "SMALL");将s设置成Size.SMALL.
Size[] values = Size.values();返回所有元素进数组。ordinal方法返回常量在枚举中的位置。

反射!
可以运行中分析类的能力
运行中查看对象
实现数组的操作代码
领用method对象

Class类
String className= "java.util.Date",
Class cl= Class.forName(className);
可以调用静态方法forname获得类名对应的class对象。==可以用来对类对象的比较。e.getClass().newInstance()可以快速建立一个类的实例。这个方法调用的是默认的构造器。如果没有默认构造器则抛出异常。

Field,Method,Constructor,三个类属于java.lang.reflect放射包,分别用来描述类的域,方法还有构造器。getname返回项目名称,field的gettyp返回域所属类型的Class对象。getModifiers方法返回一个整数数值,用不同的位开关描述public,static这样的使用情况。Modifer类的静态方法分析返回的整形数值,例如isPublic,isPrivate。Class中的方法getFields,getMethods,getConstructors方法将分别返回类提供的public域,方法和构造器数组。其中还包括超类的成员。Class还有getDeclareFields,getDeclareMethods,getDeclaredConstructors返回类中全部域方法以及构造器,其中包括私有受保护的,但是不包括超类成员。

如果f是一个field类型的对象,object是某个包含f域的类型的对象,f.get(object)将返回一个对象,器值为object域的当前值。setAccessible方法可以允许查看私有域。f.set(object,value)可以将object对象的f域设置成新值。

利用反射编写泛型数组代码
java.lang.reflect包中的Array类允许动态的创建数组。一个由 new Object[newLength]创建的对象数组,不能转换成别的类型数组,主要问题是怎么写成一个通用的增长数组的方法,比如 Employee[] a= new Employee[100]; a=(Employee[]) arrayGrow(a); 那么这个方法是 给他什么样类型的数组,都能当成参数接受,然后得到新数组后还能转换成原来参数的数组类型。但是如果创建数组时就是object创建的,那么java数组会记住每个元素的类型,即创建数组时new表达式中使用使用的元素类型。将一个Employee数组临时转换成object数组是可以的,然后再转换成employee数组也是可以的,但是如果一开始new的时候就是object类型,却不能转换成employee类型。需要java.lang.reflect包中的array类的一些方法。其中最关键的就是静态方法newInstance,他能够构造新数组,在调用时候必须提供两个参数,一个是数组的元素类型,一个是数组的长度。
object newArray= Array.newInstance(componentType,newLength);

这样可以扩展任何类型的数组,而不仅仅是对象数组,int[]这种基本数组也可以扩展, int[] a={1,2,3,4}; a= (int[]) goodArrayGrow(a); 这是因为把方法的参数设置成了object类型,而不是声明为object[]对象型数组。整数型数组可以转换为Object类型,却不能转换成对象数组。

 

方法指针

Method类中有一个invoke方法,允许调用包装在当前Method对象中的方法。class中的getMethod方法要给出方法名字,已经想查找方法的参数类型。

 

 

对象的克隆是创建一个新对象,且新对象的状态与原始对象的状态相同,对克隆的新对象进行修改时,不会影响原始对象的状态。

 

接口绝对不能含有实例域也不能在接口中实现方法,静态方法也不能有,但是可以有常量和静态域。提供实例域和实现方法的任务应该在实现接口的那个类来完成。

 

instanceof也可以检查这个对象是否实现了一个接口。接口中的方法自动的被设置为public一样,接口中的域将被自动设置为public static final

 

默认的克隆是浅拷贝,就是对象里面的基本类型域可以被拷贝,但是如果对象里面还有对象引用的话,那么克隆后的新对象里面的对象引用跟原来对象里面的对象引用是指向同一个地址的。也就是没有克隆包含在对象中的内部对象。

 

即使clone的默认实现能够满足需求,也应该实现cloneable接口,将clone重新定义为public,之前是保护的,并调用super.clone(),下面是一个例子

class Employee implements Cloneable{

public Employee clone() throws CloneNotSupportedException

{return (Employee) super.clone();

}}//浅拷贝

 

/*深拷贝*/

class Employee implements Cloneable{

public Employee clone() throw CloneNotSupportedException

{

Employee cloned= (Employee)super.clone();

cloned.hierDay=(Date) hireDay.clone();

return cloned;

}}

 

javax.swing.Timer是一个给定周期间隔,然后重复调用执行一个方法的类,给定的参数有两个,第一个是时间间隔,第二个是实现了ActionListener的对象。

Tookkit.getDefaultToolkit().beep();

 

内部类

内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据

内部类可以对同一保重的其他类隐藏起来。

想定义一个回调函数不想编写大量代码的时候,使用匿名内部类比较便捷。

 

在内部类里面可以这样引用外围类 OuterClass.this

在外围类的作用域之外,可以这样引用内部类 OuterClass.InnerClass 比如 TalkingClock jabberer = new TalkingClock(1000,true); TalkingClock.TimerPrinter listener = jabberer.new TimePrinter();这里TalkingClock是外围类,Timeprinter是内部类。

 

在一个方法中声明类就是局部类,不能用public,private进行声明。他的作用域被限定在声明这个局部类的块中。这样对外部世界可以完全的隐藏起来,出来声明的方法知道这个类外,其他没有任何方法知道这个局部类的存在。

局部类不仅可以访问包含他们的外部类,还可以访问包含他们的方法的局部变量,不过局部类访问方法中的局部变量的话,必须把局部变量声明为final,为什么这样可以查看Java核心第一卷227页。

 

匿名内部类

是将局部内部类的使用再深入了一步。只创建这个类的一个对象,而不必命名了。用于构建对象的任何参数都要被放在超类名后面的括号里面,语法格式为

SuperTyper object=new SuperTyper(construction parameters){

 inner class methods and data

} supertyper可以是接口,那么后面就要实现他,也可以是类,那么后面的匿名类就要扩展他。由于构造器的名字必须与类名相同,而匿名类没有名字,所以匿名类不能有构造器。而是把构造器参数传给超类构造器。尤其是在内部类实现接口的时候不能有任何构造参数。

 

静态内部类

把内部类声明为static可以取消产生的引用,就是不再引用外围类对象,也不需要引用任何其他的对象。只有内部类可以声明为私有或者静态。如果内部类对象在静态方法中构造,那么就必须使用静态内部类。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值