继承的最大好处就是为了实现代码的复用。那么,子类到底从父类获得的什么呢?java
父类的private成员不会被子类继承,子类不能访问。可是子类对象的确包含父类的私有成员。父类的 包访问成员 继承为子类的包访问成员。就好像他们直接定义在子类中同样。父类的 protected 成员继承为子类的protected 成员。就好像他们直接定义在子类中同样。父类的 public 成员继承为子类的public 成员,就好像他们直接定义在子类中同样。
实例方法ios
继承到的实例方法在子类中能够直接被使用,还需重点理解是方法的重写和重载。jvm
重写overrideide
一个继承链中,父类的方法对于子类来讲具备相同的语义,可是不一样的细节操做,所以子类须要override父类的这个方法以知足本身的需求。函数
注意的点:this
一、方法名,参数表必定和父类中的相同,返回类型相同,或者是子类。spa
一、访问权限必定不低于父类的实例方法设计
二、抛出的异常必定是父类方法抛出的异常相同,或者子类。code
若是拿C++和java对比,那么java中的实例方法默认都是virtual的(java中没有virtual这个key word),所以在java中,子类能够直接重写父类方法的任何非final实例方法,可是在C++中,除非父类使用virtual标记一个方法为虚方法,子类才能够override这个方法。对象
对于重写的方法,javac是不能肯定的具体要调用那个类的方法,而是产生特殊的字节码让jvm去动态决定什么方法。这个就是所谓的前期绑定和后期绑定的差别。
public class Test { public static void main(String [] args){ Object o = new SubClass(); o.toString(); } } class SubClass extends Object { public String toString() //重写Object 的toString方法 { return "SubClass"; } }
Compiled from "Test.java" public class Test { public Test(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class SubClass 3: dup 4: invokespecial #3 // Method SubClass."<init>":()V 7: astore_1 8: aload_1 9: invokevirtual #4 // Method java/lang/Object.toString:()Ljava/lang/String; 12: pop 13: return }
其中3处红色标记 的代码,重要的区别就是invokespecial 和 invokevirtual :invokespecial 表明前期绑定,在编译期就能决定调用什么方法,由javac肯定调用什么方法。invokevirtual 则是方法的后期绑定,由JVM决定调用什么方法。
第一处是Test类的构造函数调用父类Object的构造函数,编译期肯定,他是前期绑定。
第二处是由于new 了一个SubClass对象,调用SubClass的构造函数,编译期肯定,他也是前期绑定的。
第三处是由于咱们的 Object o 引用了重写了toString方法的SubClass对象,javac不能知道具体调用Object中的toString,仍是SubClass中的toString,因而产生特殊代码让JVM去决定。
修饰为 static 、 final 、private 的方法必定是前期绑定,由于他们根本都不存在override。
JVM须要在运行时动态决定调用那个版本的方法,这个过程对JVM来讲就是 virtual method lookup(虚方法查找)。JVM将会从实际对象所属的类 和 他的最近的父类中查找。若是本身定义了,则调用本身的版本,若是没有则调用父类的版本。
重载overload
重载的定义:函数重载是指在同一做用域内,能够有一组具备相同函数名,不一样参数列表的函数,这组函数被称为重载函数。
注意:重载与否,不考虑函数的返回类型。C++也是如此。也就是说,2个函数的返回类型同不一样都不影响他们能不能造成重载,只要他们函数名相同,参数表不一样就知足重载。
Java是默认是支持跨类重载的。可是C++就默认不支持在子类中重载父类的实例方法。那也就是说:java中的实例方法会自动导入到子类的做用域中,而C++则不是。
public class Test { public static void main(String[] args) { Derive d = new Derive(); d.print("hello", 2); d.print("world");
/* output
hello
hello
world
world
world
world
world
*/
} } class Base { public void print(String msg) { for(int i=0;i<5;++i) { System.out.println(msg); } } } class Derive extends Base { public void print(String msg,int times) //在子类中重载父类方法 { for(int i=0;i<times;++i) { System.out.println(msg); } } }
对于C++
#include<iostream> #include<string> using namespace std; class Base { public : void print(const string& msg) const { for(int i=0;i<5;++i) { std::cout<<msg<<std::endl; } } }; class Derive:public Base { public : /* *须要使用using Base::print将父类中的版本引如到子类的做用域中,这样才能造成跨类重载,不然子类在使用一个参数版本的print函数时,会出现如下编译错误: * * error: no matching function for call to ‘Derive::print(const char [6])’ *意思是编译器在Derive类中找不到print(const char [6])版本的函数 * */ using Base::print; void print(const string& msg,const int times) const { for(int i=0;i<times;++i) { std::cout<<msg<<std::endl; } } }; int main() { Derive d ; d.print("hello",2); d.print("world"); }
实例字段
实例字段没有什么要说的,要说的就是实例字段的隐藏了:在子类中定义一个和父类同名的字段,那么子类中的名称将会隐藏父类中的同名字段。
几乎没有人使用这个技术,若是用到了,那么说明代码设计有问题(bad code)。
class Base { protected int i = 100; } class Derive extends Base { private int i = 1000; //隐藏了父类字段 i public void foo() { System.out.println(i); //表明this.i System.out.println(this.i); System.out.println(super.i); //使用父类被隐藏的i } }
使用父类被隐藏的字段,也可使用cast,这是最终极的手段。由于super只能引用最近父类的成员,而不能引用父类的父类的成员。但使用cast能够作到。
class A { protected int i = 100; } class B extends A { protected int i = 1000; } class C extends B { private int i = 10000; public void foo() { System.out.println("this.i:"+this.i); //10000 System.out.println("B.this.i:"+ ((B)this).i ); //1000 System.out.println("A.this.i:"+ ((A)this).i ); //100 } }
static会被子类继承吗?答案是会。他们会被继承为子类的static成员,而不是子类实例的成员。
一样,private static成员不会被继承,只有 包访问 权限 ,protected public 成员才会被继承。
父类的private成员不会被子类继承,子类不能访问。父类的 包访问成员 继承为子类的包访问成员。就好像他们直接定义在子类中同样。父类的 protected 成员继承为子类的protected 成员。就好像他们直接定义在子类中同样。父类的 public 成员继承为子类的public 成员,就好像他们直接定义在子类中同样。
static 成员一样也可使用实例成员的访问修饰符 public ,包访问,protected , priavcte。
static方法
static方法不能被override,只能被隐藏。
static字段
和实例字段同样,static字段也能够被隐藏。若是要引用被隐藏的父类static字段,则须要显式的经过父类的类名来使用。隐藏static字段一般也最好不要使用。
构造函数不能继承,可是子类必定能够(也必须)借用父类的构造函数。java保证:除了Object类对象,每个类的实例在构造时,先去调用父类的构造函数。
咱们自定义类的构造函数的第一句必定是super(xx,...),若是不是,那么第一句就必定是this(xx,...)去调用本类的另外一个构造函数。
若是子类构造函数不显式的调用super(),那么,javac会自动插入super(),也就是父类无参数的构造函数。
对于构造函数,其实类中全部构造函数都是隐式static的。很明显的例证就是 构造函数無需通過实例就能够调用。
欢迎转载,请注明出处:www.cnblogs.com/lulipro
为了得到更好的阅读体验,请访问原博客地址。
限于本人水平,若是文章和代码有表述不当之处,还请不吝赐教。
代码钢琴家