【Java开发语言 05】第五章 高级类特性(二)(关键字static+单例设计模式+类成员四:初始化块+关键字final+抽象类+模板方法设计模式+接口+工厂方法和代理模式+类成员五:内部类)

本文详细介绍了Java中的静态变量与方法、单例设计模式(饿汉式和懒汉式)、main方法语法、初始化块、final关键字、抽象类与接口、模板方法设计模式以及内部类和匿名内部类的应用。内容涵盖类的静态成员、对象实例化过程、代码块执行顺序、单例模式的实现方式以及多重继承的变通实现。此外,还探讨了工厂方法和代理模式的概念。
摘要由CSDN通过智能技术生成

在这里插入图片描述

1 关键字:static

如果将一个字段定义为static,每个类只有一个这样的字段。而对于非静态的实例字段,每个对象都有自己的一个副本。
在这里插入图片描述
例如给Eployee员工类添加一个实例字段id和一个静态字段nextId:

public class Employee {
    public static int nextId = 1;
    public int id;
}

每一个Employee对象都有一个自己的id字段,即如果创建1000个Employee对象,则有1000个实例字段id,分别对应每一个对象。但是只有一个静态字段nextId
但这个类的所有实例将共享一个nextId。他属于类,而不属于任何单个的对象

  • 不带static的实例变量,需要实例化才能调用,对象.变量名;对象.方法名
    • 如下例子:变量radius为不加staic的实例变量,即只有实例化new一个对象,才可以对象.radius进行调用。且同一个类的两个对象c1和c2也有各自的radius变量,完全不可能互相影响
      在这里插入图片描述
 		Circle c1 = new Circle(2.0);
        Circle c2 = new Circle(3.0);

        System.out.println("c1的面积 = "+c1.findArea());//c1的面积 = 12.566370614359172
        System.out.println("c2的面积 + "+c2.findArea());//c2的面积 + 28.274333882308138

类变量、类方法

  • static修饰的静态变量,无需实例化,用类名就可调用,对象名也可以。类.静态变量名;类.静态方法名; 对象.静态变量名;对象.静态方法名
    • 创建Chinese类用来表示中国人,每个实例化的对象国际都为China,有几个对象就要赋值China几次,十分麻烦。可以写作静态变量,使该类的所有对象都共享国籍country这一属性。
      在这里插入图片描述
public class Chinese {
    public Chinese(String name, int age){
        this.country = "China";
        this.name = name;
        this.age = age;

    }

    static String country;
    String name;
    int age;

    public static void test(){
        System.out.println("Chinese的类方法test");
    }
    public void people(){
        System.out.println(this.name+"的实例方法");
    }

}

 		Chinese p1 = new Chinese("张三",3);

        System.out.println(Chinese.country);//类名调用China
        System.out.println(p1.country);//China

        //System.out.println(Chinese.name);
        System.out.println(p1.name);//张三

        //System.out.println(Chinese.age);
        System.out.println(p1.age);//3

        Chinese.test();//类名调用,Chinese的类方法test
        p1.people();//张三的实例方法

在这里插入图片描述

  • 静态属性自增来统计中国人数
    因为静态属性为类变量,全类对象共享。写静态变量count,需要每实例化一个对象,人数+1,可以写在构造方法里自增。
public class Chinese {
    public Chinese(String name, int age){
        this.country = "China";
        this.name = name;
        this.age = age;
        count++;//人数自增

    }

    static String country;
    static int count;
    String name;
    int age;
}
Chinese p1 = new Chinese("张三",3);
Chinese p2 = new Chinese("李四",4);
System.out.println("中国人数为"+Chinese.count);//2

在这里插入图片描述

  • 类方法(静态方法)
    • 将经常使用的“判断字符串是否为空”的判断抽取到工具类中做一个方法
    • 注意:静态方法中,不可使用this,super,因为其表示对象
public class Utils {
    public static boolean isEmpty(String str){
        if(str != null && !str.equals("")){
            return false;
        }
        return true;
    }
}
String str = "234fhg";
String s = null;
System.out.println(Utils.isEmpty(str));//false
System.out.println(Utils.isEmpty(s));//true
  • 静态方法不可以调用非静态属性和方法,非静态方法可以调用静态方法
    • 很好理解,调用类方法时不一定有实例对象 ,所以不可
package com.qx.day09;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: xuexuezi
 * @Date: 2022/08/14/23:38
 * @Description:
 */
public class Circle {
    public Circle(double radius) {
        getName();//个人感觉这句没啥用,或许是为了对应属性初始化
        this.radius = radius;
    }

    private double radius;
    private static String name ="这是一个圆";

    public static String getName(){
        return name;//写不了this.name。因为静态方法中不可以出现this,super
    }


    public double findArea() {
        return Math.PI * radius * radius;
    }

    public void display(){
        System.out.println("name:"+getName()+"radius:"+this.radius+"Area:"+findArea());
    }
}

System.out.println(Circle.getName());//这是一个圆

        Circle c1 = new Circle(5.7);//name:这是一个圆radius:5.7Area:102.07034531513239
        Circle c2 = new Circle(8.9);//name:这是一个圆radius:8.9Area:248.84555409084754
        c1.display();
        c2.display();

在这里插入图片描述
在这里插入图片描述

//本类中调用
public class Person {
    private int id;
    public static int total = 0;
    public Person(){
        total++;
        id = total;
    }
    public static void main(String args[]){
        Person Tom = new Person();
        Tom.id = 0;
        total = 100;//不用创建对象就可以访问静态成员
    }
}
//其他类中调用
public class OtherClass {
    public static void main(String args[]){
        Person.total = 100;//不用创建对象就可以访问静态成员
        //访问方式:类名.类属性,类名.类方法
        System.out.println(Person.total);//100

        Person c = new Person();
        System.out.println(c.total);//101
        System.out.println(c.id);//101

        Person d = new Person();
        System.out.println(d.total);//102
        System.out.println(d.id);//102
        //每创建一个对象,total++
    }
}

在这里插入图片描述
在这里插入图片描述

单例(Singleton)设计模式

  • 单例模式,软件的运行有且仅有一个实例化对象,(只会new一次)
    • 使用单例模式解决什么问题?一般都是new对象太费劲,例如实例化对象的创建要消耗大量的时间和资源
      在这里插入图片描述

饿汉式单例模式

  • 指在有人调用类之前,先在类内部创建,并实例化一个对象,等着调用时返回即可
public class Single {

   //构造方法私有化,不允许调用该类new对象
    private Single(){

    }
    //在类中new一次私有的Single对象
    private static Single single = new Single();

    //返回创建好的实例对象
    public static Single getInstance(){
        return single;
    }
}
//main中调用
		Single s1 = Single.getInstance();
        Single s2 = Single.getInstance();
        Single s3 = Single.getInstance();
        //已知equals方法比较普通类对象时,比较的是对象地址,必须得为同一个对象才相等为true
        //==比较基本数据类型是内容,引用类比较的也是对象地址
        System.out.println(s1.equals(s2));//true
        System.out.println(s2.equals(s3));//true
        System.out.println(s1 == s2);//true
        System.out.println(s2 == s3);//true

在这里插入图片描述
在这里插入图片描述

懒汉式单例模式

  • 指开始在类中出创建的对象为null,直到第一个人调用时,才new一个对象,之后所有调用都用这个第一次new的对象
public class Single2 {
    //私有化构造,让外面不能直接new
    private Single2(){

    }

    //创建对象为null,并不实例化
    private static Single2 single2 = null;

    //若是头次调用则new一个对象,
    public static Single2 getInstance(){
        if(single2 == null){
            single2 = new Single2();
        }
        return single2;
    }

}
		Single2 s4 = Single2.getInstance();
        Single2 s5 = Single2.getInstance();
        Single2 s6 = Single2.getInstance();

        System.out.println(s4.equals(s5));//true
        System.out.println(s5.equals(s6));//true
        System.out.println(s4 == s5);//true
        System.out.println(s5 == s6);//true

在这里插入图片描述

在这里插入图片描述

饿汉式单例模式和懒汉式单例模式的区别,在于什么时候new这个对象

  • 饿汉式,是在类加载之后,还没有人调用的时候,就先new好一个对象,以后不论谁来调用getInstance方法,都是直接返回之前new好的那个对象
  • 懒汉式,是在第一次有人调用getInstance方法来new对象,以后再有人调用getInstance方法直接就返回之前第一次new好的对象

个人思考: 单例模式中创建本类对象的属性,和返回对象的方法都为static修饰?
用意应该是作为类属性和类方法,该类中只得存在一个,而且不允许外部调用new对象,所以要写为类方法。且该属性为本类实例化对象,不能通过对象.对象调用,取得该属性的方法自然也不好通过对象.方法调用得到对象。且单例设计模式本来就只有一个对象,通过类方法取得作为类属性的实例对象合情合理。

2 理解main方法的语法

在这里插入图片描述
在这里插入图片描述

  • 在D盘下创建TestMain.java文件
    在这里插入图片描述
public class TestMain {
    public static void main(String[] args){
        for(String s: args){
            System.out.println(s);
        }
    }
}

左下角cmd打开命令控制符
D:进入D盘目录
javac TestMain.java 编译TestMain类后生成TestMain.class文件
java TestMain 456 hyj 89j yhd运行类,传参数[456,hyj,89j,yhd]

在这里插入图片描述

  • 运行如图,打印传入的参数
    在这里插入图片描述

3 类的成员之四:初始化块

  • 普通初始化块:创建对象时隐式调用
  • 静态初始化块:类加载时隐式调用

静态初始化块只调用一次(类加载时),而普通初始化块可以调用多次,随着对象的创建而加载

	{
        System.out.println("这是一个代码块");
    }
    
    static{
        System.out.println("这是一个静态代码块");
    }

在这里插入图片描述

  • 非静态代码块
    • 下例验证实例化对象时,程序的执行顺序为声明成员变量的默认值String name;—>静态代码块—>非静态的代码块—>显示构造器
public class Person {
    String name;

	//显示构造器
    public Person(){
        this.name = "张三";
        System.out.println("执行的是构造方法");
    }

    //非静态的代码块
    {
        System.out.println("执行的是非静态代码块");
    }
}
 public static void main(String[] args) {
        Person p1 = new Person();
    }

在这里插入图片描述
在这里插入图片描述

  • 静态代码块
    • 静态代码块中只能用静态属性和方法。且只会执行一次,不管new多少次对象。

在这里插入图片描述
在这里插入图片描述

public class Person {
    String name;
    static int age;

    public Person(){
        this.name = "张三";
        System.out.println("执行的是构造方法");
    }

    //非静态的代码块
    {
        System.out.println("执行的是非静态代码块1");
    }
    {
        System.out.println("执行的是非静态代码块2");
    }
    {
        System.out.println("执行的是非静态代码块3");
    }

    //静态代码块
    static{
        //这里只能使用静态static修饰的属性和方法
        age = 1;
        showAge();
        System.out.println("====执行的是静态代码块1====");
    }

    {
        System.out.println("执行的是非静态代码块4");
    }
    static{
        System.out.println("====执行的是静态代码块2====");
    }

    public static void showAge(){
        System.out.println(age);
    }
}
 public static void main(String[] args) {
        new Person();
        new Person();
        new Person();
    }

在这里插入图片描述
在这里插入图片描述

  • 在匿名内部类中用代码块代替构造方法
    • Student p = new Student(){};来构造匿名内部类,为Student类的匿名子类
    • 因为匿名内部类没有名字,不能创建对象,所以用代码块初始化
      在这里插入图片描述
public class Student {
    String name;
    String schoolName;

    public Student(){
        this.name = "学生姓名";
        this.schoolName = "学校名称";
        System.out.println("执行的是构造方法");
    }

    public void test(){
        System.out.println("Student的test方法");
    }
}
public static void main(String[] args) {
//        new Person();
//        new Person();
//        new Person();

        //匿名内部类
        Student p = new Student(){
            //这是一个Student的匿名子类
            //问题?现在想把name改成李四,但是不想动Student的代码
            {
                //在匿名内部类中,用代码块代替构造方法,为类属性初始化
                super.name = "李四";
                super.schoolName = "第一小学";
                System.out.println("匿名子类中用代码块替代构造器");
            }

            @Override
            public void test() {
                System.out.println("在Student的匿名子类中重写test方法");
            }
        };

        System.out.println(p.name+","+p.schoolName);
        p.test();
    }

在这里插入图片描述

4 关键字:final

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • final修饰的变量必须显示赋值,且不可后期更改
    • 常量名称采用全大写,多个单词用_分隔的方式
  • final修饰的方法不可以被子类继承后重写该方法
  • final修饰类,则该类不可被继承
public class TestPerson {
 	public TestPerson(){
        count = 9;
    }
    int age;//普通变量可以不赋值
    
	final int count;//在构造器中初始化常量也可以

    final String PERSON_NAME = "哈哈";//final修饰的变量是就是全局常量
    //final String PERSON_NAME;//1.错,final修饰的变量为常量,初始化时必须显示赋值

    final static String NAME = "全局常量1";//final static修饰的变量为全局常量

    final Person p = new Person();
    //p.name = "新名字";//1.写法错误,final修饰的对象也不能修改啥

    public void test(){
        //PERSON_NAME = "87";//1.错,final修饰的变量为常量不可再赋值
        System.out.println("普通方法test");
    }

    public final void test2(){
        System.out.println("父类的final方法");
    }
}
final class TestOverride extends TestPerson{
    @Override
    public void test() {
        super.test();
    }

//    @Override
//    public final void test2(){
//        System.out.println("父类的final方法");
//    }
    //2. 错误,final修饰的方法不可被重写
}

//class TestOverride2 extends TestOverride{
//
//}//3. 错误,TestOverride被final修饰,不可被继承

final static 和 final的区别、静态常量与常量

原文链接
static+final称为全局常量

  • 静态常量,编译期常量,编译时就确定值。(Java代码执行顺序,先编译为class文件,再用虚拟机加载class文件执行)
  • 放于方法区中的静态常量池。
  • 在编译阶段存入调用类的常量池中
  • 如果调用此常量的类不是定义常量的类,那么不会初始化定义常量的类,因为在编译阶段通过常量传播优化,已经将常量存到调用类的常量池中了

final

  • 常量,类加载时确定或者更靠后。
  • 当用final作用于类的成员变量时,成员变量(注意是类的成员变量,局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值
  • 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;
  • 如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。但是它指向的对象的内容是可变的
public class NotInit {
    public static void main(String[] args) {
        //经过编译优化,静态常量已经存到NotInit类自身常量池中,不会加载ConstC
        System.out.println(ConstC.str);
    }
}
class ConstC{
    public ConstC(){
        count = 90;
        System.out.println("ConstC ");
    }

    static{
        age = 50;
        System.out.println("ConstC init!");
    }

    public static final String str = "全局常量";
    public static int age;
    public int count;

}

5 抽象类

  • 只要类中有一个抽象的方法,那么这个类就必须是一个抽象类。
  • 或者将抽象方法的声明写为普通方法,并实现方法。类就不用作为抽象类
    在这里插入图片描述
    个人理解:
  • abstract不能修饰final的方法,因为final方法不能被重写。但abstract方法要被重写实现
  • abstract不能修饰属性,因为属性无需实现,没有抽象的概念
  • absract不能修饰私有方法,因为private修饰的方式无法在子类中用,但absract需要子类中重写方法
  • abstract不能修饰构造器,因为构造器必须实现,不能抽象
  • abstract不能修饰静态方法,static修饰的是静态方法,可以直接被类调用; 而abstract修饰的类中只有方法名,无方法体,不能被直接调用,故abstract不能和static一起使用
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 抽象类引用接收子类对象
    在这里插入图片描述

问题:
1.为什么抽象类不可以使用final关键字声明?
抽象类不能被实例。抽象类是用来继承,子类必须重写父类的抽象方法,并提供方法体)
2.一个抽象类中可以定义构造器吗?
抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。

  • 练习1:编写一个Employee类,声明为抽象类,包含如下三个属性:name,id,salary。提供必要的构造器和抽象方法:work()。对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。请使用继承的思想,设计CommonEmployee类和Manager类,要求类中提供必要的方法进行属性访问。
  • 写的过程中发现,抽象类一定要有无参构造。只写了有参构造,子类继承后报错There is no default constructor available in 'com.qx.day09.Employee'
public abstract class Employee {
    public Employee(int id, String name, String salary){
        this.id = id;
        this.name = name;
        this.salary = salary;
    }
    public Employee(){

    }

    int id;
    String name;
    String salary;

    public abstract void work();


}
class CommonEmplyee extends Employee{
    @Override
    public void work() {
        System.out.println("普通员工工作");
    }

    public int getId(){
        return id;
    }

    public String getNmae(){
        return name;
    }

    public String getSalary(){
        return salary;
    }
}

class Manager extends Employee{

    int bonus;

    @Override
    public void work() {
        System.out.println("管理员工作");
    }
    public int getId(){
        return id;
    }

    public String getNmae(){
        return name;
    }

    public String getSalary(){
        return salary;
    }
    public int getBonus(){
        return bonus;
    }
}
 		Employee e1 = new CommonEmployee();
        CommonEmployee e2 = new CommonEmployee();

        Employee e3 = new Manager();
        Manager e4 = new Manager();
        e1.work();
        e2.work();

        e3.work();
        e4.work();

在这里插入图片描述

  • 练习2
    • 构造动物抽象类,由鱼和狗继承并实现行走方式的抽象方法
public abstract class Animal {

    //设置动物行走方式
    public abstract void move();
}

//三个动物类继承抽象类并重写抽象方法
class Fish extends Animal {

    @Override
    public void move() {
        System.out.println(getClass().getName() + "的行走方式是游");
    }
}

class Dog extends Animal {

    @Override
    public void move() {
        System.out.println(getClass().getName() + "行走方式是跑");

    }
}

class Brid extends Animal {

    @Override
    public void move() {
        System.out.println(getClass().getName() + "行走方式是飞");
    }
}


    • 调用时,抽象类引用可接收自己的子类实例化对象(子类如果是抽象类,不可实例化对象)
		
        Animal fish = new Fish();
        Fish fish2 = new Fish();
        fish.move();
        fish2.move();

        Animal dog = new Dog();
        Dog dog2 = new Dog();
        dog.move();
        dog2.move();

        Animal bird = new Brid();
        Brid bird2 = new Brid();
        bird.move();
        bird2.move();

在这里插入图片描述

模板方法设计模式(TeplateMethod)

在这里插入图片描述

  • 构造抽象类Template创建final方法getTime统计方法code执行时间,code为抽象方法,子类可以自由实现。
    • 如子类SubTemplate定义code为一个10000次一句的循环,用getTime统计code执行时间
public abstract class Template {
    public final void getTime(){
        long start = System.currentTimeMillis();
        code();
        long end = System.currentTimeMillis();
        System.out.println("执行时间是:"+(end-start));
    }
    public abstract void code();
}

class SubTemplate extends Template{
    @Override
    public void code() {
        int i = 1000000;
        while(i > 0){
            i--;
        }
    }
}

		SubTemplate s1 = new SubTemplate();
        s1.getTime();

在这里插入图片描述

6 更彻底的抽象:接口(interface)

定义接口,类实现接口,接口继承接口

在这里插入图片描述
在这里插入图片描述

  • 一个类同时实现两个接口
    在这里插入图片描述
  • 一个类既继承父类,又实现接口。那么先继承,再实现
    在这里插入图片描述

接口没有构造器,抽象类有构造器。但都不可以实例化,即new一个对象

一个类可以实现多个接口,如果接口之间有相同的方法,那么实现的是哪个方法,还是同化了

接口的实际应用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public interface Cook {
    void fry();
}
public interface Sing {
    void singsing();
}

public abstract class Person2 {
    int age;
    String name;
    String sex;
    public abstract void showInfo();
}

public class TeacherSC extends Person2 implements Cook,Sing {
    String course;

    public void setInfo(String name, int age, String sex, String course){
        super.name = name;
        super.age = age;
        super.sex = sex;

        this.course = course;
    }

    @Override
    public void showInfo() {
        System.out.println("会唱歌会做菜的老师信息:");
        System.out.println("姓名:"+name+",年龄:"+age+",性别"+sex);
        System.out.println("任教课程:"+course);
        fry();
        singsing();
    }

    @Override
    public void fry() {
        System.out.println(super.name+"会做川菜");
    }

    @Override
    public void singsing() {
        System.out.println(this.name+"会唱流行歌");
    }
}

		TeacherSC t1 = new TeacherSC();
        t1.setInfo("艾丽",25,"女","物理");
        t1.showInfo();

在这里插入图片描述

接口的其他问题

  • 接口可以继承接口
    在这里插入图片描述
    在这里插入图片描述
  • 抽象类是对于一类事物的高度抽象,其中既有属性也有方法接口是对方法的抽象,也就是对一系列动作的抽象
  • 当需要对一类事物抽象的时候,应该是使用抽象类,好形成一个父类
  • 当需要对一系列的动作抽象,就使用接口,需要使用这些动作的类去实现相应的接口即可。
  • 抽象类可以继承接口,不实现接口的所有抽象方法
  • ?抽象类与接口的用处区别
    如果abstract父类增加了抽象方法,子类必须增加实现该抽象方法,或将子类改为abstract,如果类已经投入使用,这样会很不方便。
    可以采用父类新建接口,新增抽象方法。子类extends父类,并implements实现接口

在这里插入图片描述

工厂方法(FactoryMethod)和代理模式(Proxy)

在这里插入图片描述
在这里插入图片描述

  • 宝马车的产品接口
public interface BWM {
    //产品的信息介绍
    //车的发动方式
    void showInfo();
}
class BWM3 implements BWM{
    @Override
    public void showInfo() {
        System.out.println("这个是宝马3系");
    }
}

class BWM5 implements BWM{
    @Override
    public void showInfo() {
        System.out.println("这个是宝马5系");
    }
}

class BWM7 implements BWM{
    @Override
    public void showInfo() {
        System.out.println("这个是宝马7系");
    }
}
  • 汽车生产工厂接口
public interface BWMFactory {
    BWM productBWM();
}
class BWM3Factory implements BWMFactory{

    @Override
    public BWM productBWM() {
        System.out.println("生产宝马3系车,new一个BWM3对象并返回");
        return new BWM3();
    }
}

class BWM5Factory implements BWMFactory{

    @Override
    public BWM productBWM() {
        System.out.println("生产宝马5系车,new一个BWM5对象并返回");
        return new BWM5();
    }
}

class BWM7Factory implements BWMFactory{

    @Override
    public BWM productBWM() {
        System.out.println("生产宝马7系车,new一个BWM7对象并返回");
        return new BWM7();
    }
}
  • main中调用测试
 //这是开发人员B的工作
        BWM b3 = new BWM3Factory().productBWM();
        b3.showInfo();

        BWM b5 = new BWM5Factory().productBWM();
        b5.showInfo();

        BWM b7 = new BWM7Factory().productBWM();
        b7.showInfo();

在这里插入图片描述

  • 总结:通过工厂把new对象给隔离,通过产品的接口可以接受不同实际产品的实现类
    在这里插入图片描述

7 类的成员之五:内部类

  • 内部类前可用修饰符static,final,private,protected
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 例子
    • 在内部类中修改外部类的变量内容,包括外部类的私有属性和方法
    • 内部类不能和自己的外部类同名
    • 在内部类中访问外部类的属性 外部类名.this.a = 80;在内部类中访问自己的属性,this.a = 10;
    • 在外部类中要使用自己的内部类的方法,得先new内部类对象。 内部类名 b = new 内部类名(); b.ma(); b.a;
//外部类和内部类有同名属性时,在内外区分两个同名属性
public class A {

    private int a = 0;
    public void showInfo(){
    //外部类要用自己的内部类的方法,得先new内部类的对象
        InnerB b = new InnerB();
        System.out.println("");
        b.ma();//在外部类方法中调用内部类方法

        System.out.println("内外部类同名属性,内部属性a = "+ b.a);
        System.out.println("内外部类同名属性,外部属性a = "+ a);
    }

    class InnerB{

        int a = 10;//与外部类的属性名相同,怎么在内部类中区分两个同名属性
        public void ma(){
            a = 8;
            A.this.a = 80;
            System.out.println("内外部类同名属性,内部属性a = "+a);
            System.out.println("内外部类同名属性,外部属性a = "+new A().a);

        }

    }

}
		A a = new A();
        a.showInfo();

在这里插入图片描述

    • 内部类可以为final,private,protected
public class C {
    final class InnerD{
        //不可以被继承
    }
    //外部类只能是缺省或public,内部类四种访问权限修饰符都可以
    private class InnerE extends InnerF{

    }
    protected class InnerF {

    }
}

    • 为static时,内部类中不能使用外部类的非static成员
    • 内部类不是static时,内部类中的成员不可以为static,只有在外部类或者static的内部类中才可以声明static成员
public class G {
    int a = 0;
    static int b = 0;
    static void showInfo(){

    }
    void showInfo2(){

    }
    static class InnerH{

        static int g;
        int h;
        void show(){
            //a = 9;//错误,内部类为static时,内部类中不能访问外部类的非static成员
            b = 0;//访问外部类的static成员
        }
    }
    class InnerI{
        //错误写法,非static内部类不可以定义静态成员 static int I = 0;
        int r;
        void show(){
            //内部类可以访问外部类的static成员和非static成员
            a=9;
            b=0;            
        }
    }
}

    • 为abtract类时,可以被其他内部类继承
    • abstract内部类被同一个外部类中的内部类继承
      在这里插入图片描述
public class J {
    abstract class K{
        int i = 0;

    }
    class L extends K{

        void setI(int i){
            i = 9;
        }
    }
}
//class M extends J.K{
//
//}
//class N {
//    class O extends J.L{
//
//    }
//
//}
    • 内部类最大的作用,是实现类的多重继承。类似接口也是为了实现多重继承,即一个类可以实现多个接口,中间用","隔开即可
    • 通过内部类实现多重继承的方式是,多个内部类分别继承多个不同的类,然后外部类可以随意调用内部类们继承到的方法和属性
    • 类A想同时获得类B和类C的方法,并且重写
      可以使用内部类来变相的实现类的多重继承
public class Test3 {
    class InnerA extends Aa{
         int i;
        @Override
        void testA() {
            //super.testA();
            System.out.println("内部类InnerA继承A后,重写方法A");
        }
    }
    class InnerB extends Bb{

    }
    class InnerC extends Cc{

    }

    private int k;
    void showInfo(){
        //创建内部类对象调用内部类方法
       InnerA a =  new InnerA();
       a.testA();//直接调用内部类继承到的方法,不重写就是原方法
       //或不命名直接new无名对象调用方法
       new InnerA().testA();

       new InnerB().testB();

       new InnerC().testC();

    }

}
class Aa{
    void testA(){
        System.out.println("方法A");
    }
}
class Bb{
    void testB(){
        System.out.println("方法B");
    }
}
class Cc{
    void testC(){
        System.out.println("方法C");
    }
}
//main中调用
		Test3 t3 = new Test3();
        t3.showInfo();

在这里插入图片描述

匿名内部类

在这里插入图片描述

public class Test{
	//构造匿名内部类
	Person2 p = new Person2(){
         {
            //在匿名内部类中必须用代码块代替构造方法,因为匿名内部类没有构造
            super.name = "haha";
        }
        
        int i = 0;
        void showInfo2(){  
        }
    };
}

interface Aaa{
    public abstract void fun1();
}

public class Outer {
    public static void main(String[] args){
        new Outer().calllnner(new Aaa(){
            //接口是不能new但此处比较特殊,是子类对象实现接口,只不过没有为对象取名
            public void fun1(){
                System.out.println("Implement for fun1");
            }
        });//两步写成一步了
    }
    
    public void calllnner(Aaa a){
        a.fun1();
    }
}

  • 练习
    在这里插入图片描述
    分析类结构,有构造方法Test,main方法和内部类Inner
    main中创建了类对象t。调用构造方法Test(),输出s3.a。内部类的a初值为5
    创建了内部类对象r,输出r.a,即为5

面向对象总结

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值