1、在继承中子类没有权限去调用父类中的private方法,只能调用父类中修饰为public或protected的成员方法
2、重载(overloading)在子类中将父类的成员方法的名称保留,重写成员方法的实现内容,更改成员方法的存储权限,或修改成员方法的返回类型,还可以修改方法的修饰权限(只能将修饰权限只能从小的范围到大的范围改变eg:从protected->public)还有一种特殊的方法--重写,子类与父类的成员方法返回值、方法名称、参数类型及个数完全相同,唯一不同的是方法的实现内容,这种特殊重写方式称为重写(overriding)。重写充分体现了java的多态性,不同对象执行自己对应的方法,而又可以通过向上向下转型来实现。子类重写父类还可以修改方法的返回值类型,这种重写方法需要遵循一个原则,即重写的返回值类型必须是父类中同一方法返回值类型的子类,在实例化子类对象时,java编译器会在子类构造方法中自动调用父类的无参构造方法。[下面为该问题例子]• e.g.
class A
{
public A(){
System.out.println("constructor of A");
}
}
class B extends A
{
public B(){
System.out.println("constructor of B");
}
}
public class Try extends B
{
public Try(){
System.out.println("constructor of Try");
}
public static void main(String[] args){
Try myTry = new Try();
}
}
• 运行结果如下:
constructor of A
constructor of B
constructor of Try
• 首先是顶级父类,然后是上一级父类,最后是子类。也就是说实例化子类对象时首先要实例化父类对象,然后再实例化子类对象,所以在子类构造方法访问父类的构造方法之前,父类已经完成实例化操作。在实例化子类对象时,父类无参构造方法被自动调用,但有参构造方法并不能被自动调用只能依靠super关键词显示的调用父类的构造方法。即就是必须先构造父类才能构造子类对象。在写finalize()方法时需要确保之类的最后一个动作是调用父类的finalize()方法。
3、 [对于重载、重写、重构的区分]
• 方法的重载(Overloading):JAVA中方法的重载是在一个类中发生进行的。当有多个方法具有相同的名字、不同的参数列表时,便产生了方法的重载,此时方法的返回类型与修饰符可相同与不同均无关系。参数列表的不同包括参数的类型,参数的个数,参数的顺序这三者之中至少有一项不同。当调用这些重载的方法时根据参数列表的不同来自动匹配方法,这也体现了JAVA的多态性。重载的类型有:参数个数不同,参数类型不同,参数顺序不同,而单单返回值类型不同并不能作为方法区分的条件,方法(函数)区分的条件为函数名称,参数[不定长参数的使用e.g. 返回值 方法名(参数类型…参数名称) e.g. public static int add(int…args) 方法体中用args.length 来确定传入参数的多少,就行将参数存入不定长数组相同]
例如:
public class Person{
public void say(){
}
private void say(String name,int age){
System.out.println("方法的重载1");
}
public void say(int age,String name){
System.out.println("方法的重载2");
}
public String say(int age,String name,String sex){
System.out.println("方法的重载3");
return name;
}
}
• 方法的重写(Overriding):JAVA中方法的重写时发生在子类继承父类的方式产生的。当子类继承父类的方法时相对父类的方法作一定的修改,这时就用到了方法的重写。在子类中进行方法的重写时,要求子类中重写的方法的访问修饰符,返回类型,方法名,以及参数列表必须与父类的相同,否则编译将出错。有一种情况除外:即当子类中重写的方法的返回类型是父类的返回类型(返回值)的子类,此时也可进行方法的重写(但此法实行于JAVA5之后),如子类的返回类型为String,而父类的为Object。如果子类的返回类型是父类中返回类型的父类或者返回类型是基本数据类型,此时编译将会报错。此时若还想用父类的方法,可用super关键字来调用。例如:
public class Person{
public void say(String name,int age){
System.out.println("方法的重写");
}
}
public class Student extends Person{
public void say(int age,String name){
super.say(name, age);
System.out.println("测试方法的重写");
}
}
• 重构:千万不要把重构理解为“构造方法的重载”。在软件工程中,重构是说程序员为了对已有程序在尽量不改变接口的前提下,进行去除bug,提高效率,增加新的功能等等重新编写代码的工作从而调整软件结构,改进代码质量。总结:方法的重载是JAVA的多态性在个类中的体现,而方法的重写是JAVA的多态性在父类与子类(即类与类)之间的实现,重构是发生在软件工程中的,不要与构造方法中的重载混淆。
4、[对于向上转型和向下转型的区分]对于“向下转型的父类对象必须是子类对象实例”这句话的理解,以及instanceof的用法
向上转型总是无害的(安全的),即就是将具有特点,具体的类向其继承的抽象的,不具体的类转化,比如平行四边形类向四边形类转化,这种转型是不会报错的体现了java的多态性,e.g.:Quadrangle obj = new Parallelogram(); 而向下转型是将其继承的抽象的,不具体的类向具有特点,具体的类转化,这样会丢失信息,如直接将四边形当做平行四边形e.g.:Parallelogram obj = new Quadrangle(); 编译器会直接报错,抛出ClassCastException异常,只能使用强制类型转化 e.g.:Quadrangle q = new Quadrangle(); Parallelogram p = (Parallelogram) q;但是后期将其当做Parallelogram去使用时调用子类Parallelogram中的方法会报错,所以向下转型必须满足“向下转型的父类对象必须是子类对象实例”这个条件,而判断的方式就是使用instanceof关键词,如何理解“向下转型的父类对象必须是子类对象实例”这句话,直接看上去感觉是不可能的,但是其实是,先实例化了子类对象将其向上转型为其父类,然后又向下转型为子类,此时就很容易理解什么是“向下转型的父类对象必须是子类对象实例”这个父类对象本身必须是有子类向上转型的再将其转型回去自然不会出错, 代码如下:
Quadrangle q = new Parallelogram();
Parallelogram p = (Parallelogram) q;
这样就是对的了。 如何使用instanceof这个关键词来判断,代码如下:
Quadrangle q = new Parallelogram();
if(q instanceof Parallelogram){
Parallelogram p = (Parallelogram) q;
}
这样使用就保证了向下转型的安全性
5、抽象类不能实例化对象,且往往父类均为抽象类,使用abstract关键词抽象类的内部必须都是抽象的,且没有方法体(一般,但有时的抽象类中仅仅是因为其中的某个方法为抽象的进而曾格格类被限定为抽象的,当被继承后其中的非抽象方法即可在子类实例化对象中使用),这个方法体本身没有意义,除非其被重写,而承载这个抽象方法的抽象类必须被继承。实际上抽象类除了被继承没有任何意义。只要类中有一个方法被定义为抽象的则这个类本身必须被标记为抽象的。抽象类被继承后必须实现其中所有被标记为抽象的方法,哪怕是空实现,因而会出现代码冗余的现象,进而出现了接口,将具有特殊性的抽象方法集成在接口中让抽象父类更具有一般性,且java只允许单继承多实现,因而使得抽象类中的每个抽象方法变得不可或缺,更具有普遍性,让接口成为特殊,让需要实现接口中这些方法的子类去实现包含有这些特殊方法的接口。
• 接口是抽象类的延伸,注意接口中的方法不像抽象类中还可以有非抽象的存在,接口中纯属一种规定(强制)必须实现这些方法,因此其中的方法都没有方法体,且均为抽象的进而在接口中定义方法时省略了关键词abstract,除此之外在接口中定义的任何字段都被默认当做static和final的。接口定义时使用关键词interface即用该词替换class实现该接口使用用关键词implements,单继承类,且接口同样也是可以向上转型的,将实现了A接口的类,可以实例化该类对应的实例,并且将其向上转型为A接口的实例化对象,并且调用A中规定的方法,此时会去调用该类实现该接口的实现内容,(下面测试下A类实现I接口,B继承A实现I接口,然后将B转型为I接口调用下实现的方法看看调用的是谁,在试试B转型为A再转型为I接口调用下方法看看这个时候调动的是谁)多实现接口就好比多继承相同。
• 测试:
interface I
{
public void funcI();
}
class A implements I
{
public A(){
System.out.println("constructor of A");
}
public void funcI(){
System.out.println("A class implements the function of interface I");
}
}
class B extends A implements I
{
public B(){
super();
System.out.println("constructor of B");
}
public void funcI(){
System.out.println("B class implements the function of interface I");
}
}
public class Try
{
public static void main(String[] args){
System.out.println("B类对象实例向上转型为I接口实例后调用接口中定义的方法");
B b = new B();
I i_b = b;
i_b.funcI();
System.out.println("将B类的实例化对象向上转型为A类,再向上转型为I接口实例,调用接口中定义的方法");
A a = b;
// System.out.println("测试下由B向上转型的A是否为为B的实例使用instanceof 关键词"+(a instanceof B));
// if(a instanceof B){
// B b_a = (B)a;
// }//测试下向下转型
I i_b_a = a;
i_b_a.funcI();
System.out.println("直接生成A的实例化对象并向上转型为I接口实例,调用接口中定义的方法");
a = new A();
I i_a = a;
i_a.funcI();
// System.out.println("测试下由A是否为B的实例与上面对比使用instanceof 关键词"+(a instanceof B));
}
}
结果:
B类对象实例向上转型为I接口实例后调用接口中定义的方法
constructor of A
constructor of B
B class implements the function of interface I
将B类的实例化对象向上转型为A类,再向上转型为I接口实例,调用接口中定义的方法
B class implements the function of interface I
直接生成A的实例化对象并向上转型为I接口实例,调用接口中定义的方法
constructor of A
A class implements the function of interface I
•总结:java中的向下或向上转型(无论是类抑或是接口)都始终以原始的那个实例化对象为基准,就像例子中将B转为A再转向I并不会去调用A中的实现方法,只有一开始就实例化的是A再向上转型才会调用A中实现接口的方法。