JavaEE - 面向对象-多态、内部类

一、面向对象

17.类的多态

多态就是同一个接口,使用不同的实例而执行不同操作

多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

父类引用指向子类对象:

Parent p = new Child();

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。

Vehicle.java

public abstract class Vehicle {
    public abstract void start();
}

Car.java

public class Car extends Vehicle {
    @Override
    public void start() {
        System.out.println("一键启动,踩油门~~~");
    }
}

Wife.java

public class Wife {
    public void open(Vehicle v) {
        v.start();
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        Wife w = new Wife();
        //父类引用v中存的是子类对象在堆中地址
        Vehicle v = new Car();
        w.open(v);
    }
}

多态存在的三个必要条件:

  • 继承
  • 重写
  • 父类引用指向子类对象:Parent p = new Child();

对象转型

  1. 向上转型、自动转型:子类类型 转 父类类型

注意:

  • 向上转型就是多态
  • 可以调用父类的非私有化属性、方法
  • 不可以调用子类独有的属性和方法
  • 可以调用子类重写的父类的方法

A.java

public class A {
    String aAttr = "调用父类的非私有化属性";
    public void aMethod() {
        System.out.println("调用父类的非私有化方法");
    }
    public void method() {
        System.out.println("父类的方法");
    }
}

B.java

public class B extends A {
    String bAttr = "子类独有的属性";
    public void bMethod() {
        System.out.println("子类独有的方法");
    }
    @Override
    public void method() {
        System.out.println("调用子类重写的父类的方法");
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        A a = new B();
        //调用父类的非私有化属性
        System.out.println(a.aAttr);
        //调用子类重写的父类的方法
        a.method();
        //调用父类的非私有化方法
        a.aMethod();
        //不可以调用子类独有的属性和方法
        //a.bMethod();
        //System.out.println(a.bAttr);
    }
}
  1. 向下转型、强制转型:父类类型 转 子类类型

注意:

  • 向下转型有风险,转不好会出现ClassCastException类型转型异常

    错误示范:Dog dog = (Dog) new Animal(); --> ClassCastException类型转换异常

  • 必须使用 instanceof 判断

Animal.java

public class Animal {
}

Dog.java

public class Dog extends Animal{
}

Cat.java

public class Cat extends Animal{
}

Test.java

public class Test {
    public static void main(String[] args) {
        //向上转型
        Animal an = new Cat();
        
        if (an instanceof Dog) {//判断引用an中的对象是否是Dog类
            Dog dog = (Dog) an; //向下转型
            System.out.println(dog);
        }else if (an instanceof Cat) {//判断引用an中的对象是否是Cat类
            Cat cat = (Cat) an; //向下转型
            System.out.println(cat);
        }
    }
}

18. 内部类

在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。

1. 成员内部类

可以调用外部类所有属性

成员内部类可以拥有 private、protected、public 访问权限及包访问权限。

个人理解:由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰。

Outter.java

//外部类
public class Outter {
    private String str1 = "private属性";
    String str2 = "default属性";
    protected String str3 = "protected属性";
    public String str4 = "public属性";
    static String str5 = "static属性";
    final String str6 = "final属性";

    //成员内部类
    public class Inner {
        //如果内部类中有和外部类相同名字的属性或方法,就优先调用本类的(就近原则)
        private String str1 = "成员内部类的同名属性";
        public void method() {
            System.out.println("成员内部类里的方法");
            System.out.println(str1);
            //如果要访问外部类的同名变量/方法,  外部类.this.成员变量/方法
            System.out.println(Outter.this.str1);
            System.out.println(str2);//Outter.this.str2
            System.out.println(str3);//Outter.this.str3
            System.out.println(str4);//Outter.this.str4
            //静态属性直接类名调用
            System.out.println(str5);//Outter.str5
            System.out.println(str6);//Outter.this.str6
        }
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        //创建成员内部类的语法
        //注意:创建成员内部类会创建外部类对象
        Outter.Inner inner = new Outter().new Inner();
        inner.method();

    }
}
  • 成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。

  • 如果内部类中有和外部类相同名字的属性或方法,就优先调用本类的(就近原则)

  • 如果要访问外部类的同名变量/方法,访问形式:外部类.this.成员变量/方法

2. 静态内部类

只能调用外部类的静态属性

Outter.java

//外部类
public class Outter {
    private String str1 = "private属性";
    static String str5 = "static属性";
    //静态内部类
    public static class Inner {
        public void method() {
            System.out.println("静态内部类里的方法");
            //静态内部类不能调用外部类的非静态属性
//			System.out.println(str1);
            System.out.println(str5);//Outter.str5
        }
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        //创建静态内部类的语法
        //注意:创建静态内部类不会创建外部类对象
        Outter.Inner inner = new Outter.Inner();
        inner.method();
    }
}

静态内部类是不需要依赖于外部类的,并且它不能使用外部类的非static成员变量或方法,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。

3. 接口内部类

接口内部类 类似 静态内部类

IOutter.java

public interface IOutter {
    //接口内部类
    //默认添加static
    public class Inner {
        public void method() {
            System.out.println("接口内部类的方法");
        }
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        //创建接口内部类对象的语法
        IOutter.Inner inner = new IOutter.Inner();
        inner.method();
    }
}

4. 匿名内部类

匿名内部类是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。

匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。

使用场景:抽象类的子类对象只使用一次,就用匿名内部类
使用场景:接口的实现类对象只使用一次,就用匿名内部类

A.java

public abstract class A {
    public abstract void method();
}

I1.java

public interface I1 {
    public void method();
}

Test.java

public class Test {
    public static void main(String[] args) {
        //匿名内部类
        //1.创建匿名子类继承A,重写method
        //2.创建匿名子类的对象赋值给父类的引用(类的多态)
        A a = new A(){
            @Override
            public void method() {
            }
        };
        //匿名内部类
        //1.创建匿名类,实现I1接口中method
        //2.创建匿名类的对象赋值给接口的引用(接口的多态)
        I1 i1 = new I1() {
            @Override
            public void method() {
            }
        };
    }
}

匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。

匿名内部类在编译的时候由系统自动起名为 Outter$1.class。

5. 局部内部类

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。

局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的。

Outter.java

//外部类
public class Outter {
    public String method() {
        //如果局部内部类中使用了该变量,JDK1.8开始会给该变量自动使用final修饰
        int i = 100;
        //局部内部类  在外部类的方法里
        class Inner {
            public String innerMethod() {
                System.out.println("局部内部类的方法");
                //局部内部类中使用了外部类的局部变量,该局部变量会自动使用final修饰该变量变成常量
                return "使用了外部类的局部变量:" + i;
            }
        }
        //创建局部内部类的对象
        Inner inner = new Inner();
        //调用局部内部类的方法
        return inner.innerMethod();
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        Outter outter = new Outter();
        //调用外部类的方法时,自动调用了局部内部类的方法
        System.out.println(outter.method());
    }
}
Java Jdk1.8之后 局部内部类访问外部final变量问题

从内存中看,当方法里的局部变量所在的方法结束时,该变量即在栈内存中消失;
而内部类其实是一个类,只有内存中对它的所有引用都消失后,该内部类才“死亡”,即内部类的生命> 周期比局部变量长。
在多线程中,当方法结束后,局部内部类还在使用局部变量。
为了避免方法内的变量脱离方法而存在的现象发生,于是java规定局部内部类不能访问一般的局部> 变量。但能访问被final修饰的局部变量

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值