zoukankan      html  css  js  c++  java
  • Java笔记:多态、组合、初始化块

    1.多态

    1)Java引用变量的两种类型:一个是编译时类型,一个是运行时类型。
    编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。
    当编译时类型和运行时类型不一致的时候,就可能产生多态

    package cn.it.lsl;
    class BaseClass{
        public int book=6;
        public void base(){
            System.out.println("父类方法");
        }
        public void test(){
            System.out.println("被子类覆盖的方法");
        }
    }
    public class SubClass extends BaseClass{
        public String book = "JavaSe";
        public void test(){
            System.out.println("子类test()方法");
        }
        public void sub(){
            System.out.println("子类方法");
        }
        public static void main(String[] args) {
            BaseClass bc = new BaseClass();
            System.out.println(bc.book);
            bc.base();
            bc.test();
            System.out.println("-----------");
            SubClass sc = new SubClass();
            System.out.println(sc.book);
            sc.sub();
            sc.test();
            System.out.println("-----------");
            BaseClass ploy = new SubClass();
            System.out.println(ploy.book);        //    对象的Field不具备多态
            ploy.base();
            ploy.test();
            //ploy.sub();        //编译出错
        }
    }

    分析:
    BaseClass ploy = new SubClass();编译时类型是BaseClass,运行时类型是SubClass,当调用引用变量的test方法是,实际上执行的是SubClass类中覆盖后的test方法,这就出现多态。

    当运行时调用该引用变量的方法时,其方法总是变现出子类方法的行为特征,而不是父类的行为特征。

    所以,相同类型变量,调用同一个方法是出现不用的特性,这就是多态。

    ploy.sub();会产生错误,因为代码在编译时出错的。因为他的编译时是类型是BaseClass,编译时无法调用sub()。    (引用变量在编译阶段只能调用其编译时类型所具有的方法)

    System.out.println(ploy.book);输出6,因为对象的Field不具备多态。

    2)把一个子类对象直接赋值给父类引用变量,无须任何类型转换,这种称为向上转型。
    把一个父类对象赋值给子类引用变量时,就需要进行强制类型转换,这时候应该使用instanceof运算符保证强制类型转换更安全。

    3)instanceof

    instandeof运算符的前一个操作数是一个引用类型的变量,后一个操作数是一个类(接口),它用于判断前面的对象是否是后面的类,或子类、实现类的实例。

    instanceof运算符前面操作数的编译时类型要么与后面类相同,要么与后面的类具有父子继承关系。否则会引起编译错误。

    package cn.it.lsl;
    
    public class IntanceofDemo {
        public static void main(String[] args) {
            Object hello = "hello";
            System.out.println(hello instanceof Object);
            System.out.println(hello instanceof Math);
            String a = "hello";
            //System.out.println(a instanceof Math);
        }
    }

    在强制类型转换之前,首先判断前一个对象是否是后一个类的实例,是否可以转换成功,从而报障代码的健壮性。

    2.继承与组合

    1)尽量不要在父类构造器中调用将要被子类重写的方法。
    以下代码将发生空指针异常,Exception in thread "main" java.lang.NullPointerException

    package cn.it.lsl;
    
    class Base{
        public Base(){
            test();
        }
        public void test(){
            System.out.println("要被子类重写的方法");
        }
    }
    
    public class Sub extends Base{
        private String name;
        public void test(){
            System.out.println(name.length());
            
        }
        
        public static void main(String[] args){
            Sub s = new Sub();
        }
    }

    new Sub()的时候会先执行父类的构造器,如果父类的构造器调用了被其子类重写的方法,则变成调用被子类重写后的方法。
    即调用

    public void test(){
            System.out.println(name.length());
    }

    此时name是null,所以会抛出异常。

    2)在代码复用的时候,运用继承会带来破封装性。组合也能实现代码的复用性,采用组合能够提供更好的封装。

    3)组合是把旧类对象作为新类Field嵌入,用以实现新类的功能。一般在新类里使用private修饰被嵌入的旧类对象。

    package cn.it.lsl;
    
    class Animal{
        private void beat(){
            System.out.println("心脏跳动");
        }
        public void breath(){
            beat();
            System.out.println("呼吸");
        }
    }
    
    class Bird{
        private Animal a;
        public Bird(Animal a){
            this.a = a;
        }
        public void breath(){
            a.breath();
        }
        public void fly(){
            System.out.println("飞翔");
        }
    }
    
    public class CompositeTest {
        public static void main(String[] args) {
            Animal a = new Animal();
            Bird b = new Bird(a);
            b.breath();
            b.fly();
        }
    }

    3.初始化块

    1)初始化块可以对Java对象进行初始化操作。

    2)若初始化块带有修饰符,则修饰符只能是static,其修饰的初始化块被称为静态初始化块。

    3)当创建Java对象的时候,系统先调用该类里面的初始化块。而且在构造器之前执行。

    4)当创建一个Java对象时,系统会先执行java.lang.Object类的初始化块,开始执行java.lang.Object的构造器,在执行器父类的初始化块,在开始执行其父类的构造器...然后才是执行该类的初始化块和构造器。

    5)系统在类初始化阶段就执行了静态初始化块,而不是创建对象时才执行。所以静态初始化块总是比普通初始化块先执行。

    package cn.it.lsl;
    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("JavaSe");
            System.out.println("leaf构造器");
        }
    }
    public class Test {
        public static void main(String[] args) {
            new Leaf();
            new Leaf();
        }
    }

    执行结果:

    root静态初始化块
    mid静态初始化块
    leaf静态初始化块
    root普通初始化块
    root无参构造
    mid普通初始化块
    mid无参构造
    mid有参构造:JavaSe
    leaf普通初始化块
    leaf构造器
    root普通初始化块
    root无参构造
    mid普通初始化块
    mid无参构造
    mid有参构造:JavaSe
    leaf普通初始化块
    leaf构造器

  • 相关阅读:
    调试SQL Server的存储过程及用户定义函数
    寻找 vb.net 事务处理高级编程 的代码!!
    解析Java类和对象的初始化过程
    SQL 安装进程被挂起!
    教你成为一个受欢迎的人
    final class作用
    微软反跨站脚本库
    pdf解析
    ce'shi测试微博
    淘宝架构变化
  • 原文地址:https://www.cnblogs.com/EvanLiu/p/3130714.html
Copyright © 2011-2022 走看看