面向对象的三大特征:封装、继承、多态。java
是指将对象的状态信息都隐藏在对象内部,不容许外部程序直接访问对象内部信息,而是经过该类所提供的方法来实现对内部信息的操做和访问。封装的优势:ide
继承就是子类继承父类的特征和行为(经过关键字extends),使得子类对象(实例)具备父类的实例域和方法,或子类从父类继承方法,使得子类具备父类相同的行为。每个子类只有一个直接的父类。this
public class Test003 extends TestAll{ public Test003(){ super("003","me"); System.out.println("Test003 无参构造方法"); } public static void main(String [] args){ new Test003(); } } class TestAll extends Tester{ public TestAll(String date){ System.out.println("TestAll 带一个参数构造方法,date=" +date); } public TestAll(String date, String who){ this(date); System.out.println("TestAll 带两个参数构造方法,date="+ date +" who="+who); } } class Tester{ public Tester(){ System.out.println("Tester 无参构造方法"); } } // 打印结果为: /* Tester 无参构造方法 TestAll 带一个参数构造方法,date=003 TestAll 带两个参数构造方法,date=003 who=me Test003 无参构造方法 */
多态是同一个行为具备多个不一样表现形式或形态的能力。同一个实现接口,使用不一样的实例而执行不一样的操做。
引用变量的两种类型:编译时类型--由声明该变量时使用的类型决定;运行时类型--由实际赋给该变量的对象决定。若是编译时类型和运行时类型不一致,就可能出现多态。code
public class SubClass extends BaseClass { public String book = "READ BOOK"; public void sub(){ System.out.println("子类的普通方法"); } public void test(){ System.out.println("子类test方法 , 《"+this.book+"》"); } public static void main(String [] args){ BaseClass bc = new BaseClass(); // 编译时类型与运行时类型同样,不存在多态 System.out.println(bc.book); // 6 bc.base(); //父类普通方法 bc.test(); //父类test方法 , book=10 // bc.sub(); 编译报错,父类不能够调用子类的方法 SubClass sc = new SubClass(); // 编译时类型与运行时类型同样,不存在多态 System.out.println(sc.book); //READ BOOK sc.base(); //父类普通方法 ; 子类能够调用父类的方法 sc.sub(); //子类的普通方法 sc.test(); //子类test方法 , 《READ BOOK》 ; 覆盖了父类的test方法 BaseClass b = new SubClass(); // 编译时类型与运行时类型不同,多态发生 System.out.println(((SubClass) b).book); // READ BOOK System.out.println(b.book); // 10 b.base(); //父类普通方法 if(b instanceof BaseClass){ ((SubClass) b).sub(); // 子类的普通方法 ; 强制类型转换 } b.test(); //子类test方法 , 《READ BOOK》 } } class BaseClass{ public int book = 10; public void base(){ System.out.println("父类普通方法"); } public void test(){ System.out.println("父类test方法 , book=" + this.book); } }
该实例中 将子类的对象直接赋值给父类的引用变量b ,无需任何转型(向上转型)【子类是一种特殊的父类】。引用变量在编译阶段只能调用其编译时类型所具备的方法,但运行时则执行它运行时类型所具备的方法htm
重写:子类包含与父类同名方法的现象,也称为方法的覆盖,重写发生在子类和父类的同名方法之间。重写遵循的规则:方法名相同、形参列表相同;子类的返回值类型比父类的更小或相等。;子类方法声明抛出的异常比父类的更小或相等;子类方法的访问权限比父类的更大或相等。对象
重载:主要发生在同一个类的多个同名方法之间。重载遵循的规则:参数个数或类型不同;返回类型、修饰符也能够不同;没法以返回值类型做为重载的区分标准。(典型的重载--构造器重载)blog
共同:继承
差异:接口
注意:接口里定义的内部类、接口、枚举默认都采用public static两个修饰符,无论定义时是否指定了这俩个修饰符,系统会自动使用public static对它们进行修饰。
public class Test0804 extends Speed implements Transport{ // 抽象类和接口都不能实例化,经过子类的构造方法进行初始化, public Test0804(){ //super(); //能够隐藏 System.out.println("我是子类的无参构造方法"); } public Test0804(int i) { // 调用父类的构造方法初始化 super(i); System.out.println("我是子类的带参构造方法"); } public static void main(String [] args){ // 接口 Test0804 t = new Test0804(); System.out.println("我是静态变量:"+Transport.HEIGHT); Transport.tools(); t.run(); t.use(); System.out.println("----------------分割线-----------------"); // 抽象类 Test0804 t1 = new Test0804(2); Speed.is(); t1.has(); // 经过子类实例对象,调用父类的普通方法 System.out.println("私有变量的值为:" + t1.getCount()); t1.print(); /* 结果为: 我是无参构造方法 我是子类的无参构造方法 我是静态变量:5 我是静态方法 实现了抽象方法 run 实现了默认方法 use ----------------分割线----------------- 我是带参构造方法 我是子类的带参构造方法 抽象类的静态方法 我是普通方法 count=2 私有变量的值为:2 实现了抽象类的抽象方法 */ } // 重写接口的 run 方法 @Override public void run() { System.out.println("实现了抽象方法 run"); } // 重写接口的 use 方法 @Override public void use() { System.out.println("实现了默认方法 use"); } // 重写抽象类的 print 方法 @Override public void print() { System.out.println("实现了抽象类的抽象方法"); } } interface Transport{ /* 接口里不包含构造方法,不能定义普通成员变量,不能为普通方法提供方法的实现,不能包含初始化块 private int i =0; //编译报错 public Transport(){ // 编译报错 } public void run1(){ // 编译报错 System.out.println("我是普通方法"); } // 编译报错 { System.out.println("初始化块"); } */ int HEIGHT = 5; // 系统会自动添加 public static final static void tools(){ // 系统会自动添加 public System.out.println("我是静态方法"); } void run(); // 抽象方法 自动添加 public abstract default void use() { System.out.println("我是默认方法"); } } abstract class Speed{ private int count; // 显示声明无参构造方法 public Speed(){ System.out.println("我是无参构造方法"); } public Speed(int count){ System.out.println("我是带参构造方法"); this.count = count; } public abstract void print(); public static void is(){ System.out.println("抽象类的静态方法"); } public void has(){ System.out.println("我是普通方法 count="+ this.count); } public int getCount(){ return count; } }
继承表达式一种“是(is-a)”的关系,而组合表达的是“有(has-a)”的关系。对于继承而言,子类能够直接得到父类的public方法,程序使用子类时,将能够直接访问该子类从父类那里继承的方法;而组合则是把旧类对象做为新类的成员变量组合进来,用以实现新类的功能,用户看到的是新类的方法,而不能看到被组合对象的方法。
// ------继承------ public class InheritTest{ public static void main(String [] args){ Bird b = new Bird(); b.breath(); b.fly(); Fish f = new Fish(); f.breath(); f.swim(); } } class Animal { private void beat(){ System.out.println("心脏跳动..."); } public void breath(){ beat(); System.out.println("吸一口气,吐一口气,呼吸中..."); } } //继承Animal ,直接复用父类的 breath 方法 class Bird extends Animal{ public void fly(){ System.out.println("我在天空飞翔..."); } } //继承Animal ,直接复用父类的 breath 方法 class Fish extends Animal{ public void swim(){ System.out.println("我在水里游动..."); } }
// ------组合------ public class CompositeTest { public static void main(String [] args){ Bird1 b1 = new Bird1(new Animal1()); b1.breath(); b1.fly(); Fish1 f1 = new Fish1 (new Animal1()); f1.breath(); f1.swim(); } } class Animal1 { private void beat(){ System.out.println("心脏跳动..."); } public void breath(){ beat(); System.out.println("吸一口气,吐一口气,呼吸中..."); } } // 将原来的父类组合到原来的子类,做为子类的一个组合成分 class Bird1{ private Animal1 a; public Bird1(Animal1 a){ this.a = a; } // 直接复用 Animal1提供的 breath 方法来实现 Bird1 的 breath 方法 public void breath(){ a.breath(); } public void fly(){ System.out.println("我在天空飞翔..."); } } // 将原来的父类组合到原来的子类,做为子类的一个组合成分 class Fish1{ private Animal1 a; public Fish1(Animal1 a){ this.a = a; } // 直接复用 Animal1提供的 breath 方法来实现 Fish1 的 breath 方法 public void breath(){ a.breath(); } public void swim(){ System.out.println("我在水里游动..."); } }
Java使用构造器对单个对象进行初始化操做,使用构造器先完成整个java对象的状态初始化,而后将java对象返回给程序。与构造器做用相似的是初始化块,也能够对java对象进行初始化操做。
构造器与初始化块: 从某种程度来看,初始化块是构造器的补充,初始化块老是在构造器执行以前执行。
public class InitBlock { public static void main(String [] args){ // 类初始化阶段(编译阶段),先执行最顶层父类的静态初始化块,直到执行当前类的静态初始化块 // 对象初始化阶段(执行阶段),先执行最顶层的父类初始化块、构造方法。直到执行到当前类的初始化、构造方法。 new Leaf(); /* 结果为: Root 的静态初始化块 Mid 的静态初始化块 Leaf 的静态初始化块 Root 的普通初始化块 Root 的无参构造方法 Mid 的普通初始化块 Mid 的无参构造方法 Mid 的带参构造方法, 参数值:This is a test Leaf 的普通初始化块 执行 Leaf 构造方法 */ } } class Root{ static{ System.out.println("Root 的静态初始化块"); } { System.out.println("Root 的普通初始化块"); } public Root(){ System.out.println("Root 的无参构造方法"); } } class Mid extends Root{ static{ System.out.println("Mid 的静态初始化块"); } { System.out.println("Mid 的普通初始化块"); } public Mid(){ System.out.println("Mid 的无参构造方法"); } public Mid(String msg){ this(); System.out.println("Mid 的带参构造方法, 参数值:"+msg); } } class Leaf extends Mid{ static{ System.out.println("Leaf 的静态初始化块"); } { System.out.println("Leaf 的普通初始化块"); } public Leaf(){ super("This is a test"); System.out.println("执行 Leaf 构造方法"); } }
注:
当JVM 第一次主动使用某一个类时,系统会在类准备阶段为该类的全部静态成员变量分配内存;初始化阶段则负责初始化这些静态成员变量,初始化静态成员变量就是执行类初始化代码块或声明类成员变量时指定的初始值,它们执行顺序与源代码中的排列顺序相同
注:讲解较详细的博客 本文大部份内容来自于《JAVA疯狂讲义》