Java面向对象编程-高级

Java面向对象编程-高级

目录


main方法

解释main方法的形式: public static void main(String[] args){}

  1. main方法时虚拟机调用
  2. java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public
  3. java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static
  4. 该方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数,案例演示,接收参数
  5. java执行的程序参数1参数2参数…

类变量

基本介绍

语法:访问修饰符 static 数据类型 变量名;

类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。

类变量可以通过类名访问,也可以通过对象访问。

示例:

public class ChildGame {

    public static void main(String[] args) {
        int count = 0;
        Child child1 = new Child("白骨精");
        child1.join();
        child1.count++;
        Child child2 = new Child("狐狸精");
        child2.join();
        child2.count++;
        Child child3 = new Child("老鼠精");
        child3.join();
        child3.count++;
        //===========
        System.out.println("共有" + Child.count  + " 小孩加入了游戏...");
        System.out.println("child1.count=" + child1.count);//3
        System.out.println("child2.count=" + child2.count);//3
        System.out.println("child3.count=" + child3.count);//3
    }
}
class Child { //类
    private String name;
    // 定义一个变量 count ,是一个类变量(静态变量) static 静态!!!
    // 该变量最大的特点就是会被 Child 类的所有的对象实例共享!!!
    public static int count = 0;
    public Child(String name) {
        this.name = name;
    }
    public void join() {
        System.out.println(name + " 加入了游戏..");
    }
}

使用细节

  1. 什么时候使用类变量:当我们需要让某个类的所有对象都共享一个变量时候。
  2. 类变量和实例变量的区别:类变量由该类的所有对象共享,而实例变量是每个对象独享。
  3. 类变量在类加载时候就进行了初始化,如果没有指定初始值将执行默认初始化。如果使用方法的返回值初始化,只能使用静态方法。
  4. 类变量的声明周期是随着类的加载开始,随着类消亡而销毁。

类方法

基本介绍

语法:访问修饰符 static 数据返回类型 方法名(){}

在Java中,类方法是一种属于类类型的方法,可以使用类名访问,也可以使用对象名访问,方法体中,可以访问类变量,但不能直接访问实例变量。

使用场景:

当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法, 提高开发效率。比如:

工具类中的方法utils。Math类、Arrays类、Collections集合类看下源码可以发现都是static方法。

使用细节

  1. 类方法和普通方法都是随着类的加载而加载。将结构信息存储在方法区:类方法中无this参数,普通方法中含有this参数。
  2. 类方法可以通过类名调用,也可以通过对象名调用。普通方法和对象有关,需要通过对象名调用。
  3. 类方法中不允许使用和对象有关的的关键字,比如this和super。
  4. 类方法中只能访问静态变量和静态方法。普通方法可以访问非静态成员,也可以访问静态成员。

代码块

基本介绍

java中,用{}括起来的称为代码块,可以分为一下四种:

  1. 普通代码块:类中方法的方法体
  2. 构造代码块:构造块会在每次创建对象时被调用,优先于类构造函数执行。
  3. 静态代码块:用static{}包裹起来的代码片段。只在加载对象时候,执行一次。如果是创建对象时候,静态代码块优先于构造块执行。
  4. 同步代码块:使用synchronized(){}包裹起来的代码块,在多线程环境下,对共享数据的读写操作是需要互斥进行的,否则会导致数据的不一致性。同步代码块需要写在方法中。

构造/静态代码块

语法:

[修饰符]{
   代码
};

注意:要么没有修饰符,要么修饰符为static.

使用代码块的好处:

  1. 对构造器的一种补充机制,可以做初始化等操作。
  2. 场景:如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性。

示例:

public class CodeBlock01 {
    public static void main(String[] args) {
        Movie movie = new Movie("你好,李焕英");
        System.out.println("===============");
        Movie movie2 = new Movie("唐探3", 100, "陈思诚");
    }
}
class Movie {
    private String name;
    private double price;
    private String director;
    {
        System.out.println("电影屏幕打开...");
        System.out.println("广告开始...");
        System.out.println("电影正是开始...");
    };
    public Movie(String name) {
        System.out.println("Movie(String name) 被调用...");
        this.name = name;
    }
    public Movie(String name, double price) {

        this.name = name;
        this.price = price;
    }
    public Movie(String name, double price, String director) {
        System.out.println("Movie(String name, double price, String director) 被调用...");
        this.name = name;
        this.price = price;
        this.director = director;
    }
}

使用细节

构造器中:

    public A() {//构造器
        //隐藏了
        //super()
        //普通代码块和普通属性的初始化...
        System.out.println("A的构造器");
    }
  1. static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象, 就执行一次。
  2. 类什么时候被加载
    1. 创建对象实例时(new)
    2. 创建子类对象实例,父类也会被加载
    3. 使用类的静态成员时(静态属性,静态方法)
  3. 普通的代码块,在创建对象实例时,会被隐式的调用。被创建一次,就会调用一次。
    • 如果只是使用类的静态成员时,普通代码块并不会执行。(没有创建对象实例)
  4. 创建一个对象时,在一个类调用顺序是 (重点,难点)
    1. 调用静态代码块和静态属性初始化 (注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的先后顺序调用)
    2. 调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义先后顺序调用)
    3. 调用构造方法
  5. 构造器的最前面其实隐含了super()和调用普通代码块, 静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块执行的。
  6. 我们看一下创建一个子类对象时(继承关系),他们的调用顺序如下:
    1. 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)(类加载)
    2. 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)(类加载)
    3. 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
    4. 父类的构造方法
    5. 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
    6. 子类的构造方法
  7. 静态代码块(本质上是静态方法)只能直接调用静态成员(静态属性和静态方法),普通代码块(本质上是普通方法)可以调用任意成员。
package com.hspedu.codeblock_;

public class CodeBlockDetail04 {
    public static void main(String[] args) {
        //老师说明
        //(1) 进行类的加载
        //1.1 先加载 父类 A02 1.2 再加载 B02
        //(2) 创建对象
        //2.1 从子类的构造器开始
        B02 b02 = new B02();//对象
        System.out.println("===========================");
        new B02();

//        new C02();
    }
}

class A02 { //父类
    private static int n1 = getVal01();
    //static B02 b02 = new B02();
    static {
        System.out.println("B02.n3 "+B02.n3);
        System.out.println("A02的一个静态代码块..");//(2)
    }
    {
        System.out.println("A02的第一个普通代码块..");//(5)
    }
    public int n2 = getVal02();//普通属性的初始化
    public static int getVal01() {
        System.out.println("A02静态属性n1初始化 getVal01");//(1)
        return 10;
    }

    public int getVal02() {
        System.out.println("A02成员属性n2初始化 getVal02");//(6)
        return 10;
    }

    public A02() {//构造器
        //隐藏
        //super()
        //普通代码和普通属性的初始化......
        System.out.println("A02的构造器");//(7)
    }

}

class B02 extends A02 { //

    static int n3 = getVal03();

    static {
        System.out.println("B02的一个静态代码块..");//(4)
    }
    public int n4 = getVal04();
    {
        System.out.println("B02的第一个普通代码块..");//(9)
    }

    public static int getVal03() {
        System.out.println("B02静态属性n3初始化 getVal03");//(3)
        return 10;
    }

    public int getVal04() {
        System.out.println("B02成员属性n4初始化 getVal04");//(8)
        return 10;
    }
    //一定要慢慢的去品..
    public B02() {//构造器
        //隐藏了
        //super()
        //普通代码块和普通属性的初始化...
        System.out.println("B02的构造器");//(10)
        // TODO Auto-generated constructor stub
    }
}

运行结果

A02静态属性n1初始化 getVal01
B02.n3 0
A02的一个静态代码块..
B02静态属性n3初始化 getVal03
B02的一个静态代码块..
A02的第一个普通代码块..
A02成员属性n2初始化 getVal02
A02的构造器
B02成员属性n4初始化 getVal04
B02的第一个普通代码块..
B02的构造器
===========================
A02的第一个普通代码块..
A02成员属性n2初始化 getVal02
A02的构造器
B02成员属性n4初始化 getVal04
B02的第一个普通代码块..
B02的构造器

加上static B02 b02 = new B02();

A02静态属性n1初始化 getVal01
A02的第一个普通代码块..
A02成员属性n2初始化 getVal02
A02的构造器
B02成员属性n4初始化 getVal04
B02的第一个普通代码块..
B02的构造器
B02.n3 0
A02的一个静态代码块..
B02静态属性n3初始化 getVal03
B02的一个静态代码块..
A02的第一个普通代码块..
A02成员属性n2初始化 getVal02
A02的构造器
B02成员属性n4初始化 getVal04
B02的第一个普通代码块..
B02的构造器
===========================
A02的第一个普通代码块..
A02成员属性n2初始化 getVal02
A02的构造器
B02成员属性n4初始化 getVal04
B02的第一个普通代码块..
B02的构造器

注意:对于静态成员属性,在赋初值前,都会被默认初始化,其中引用类型会赋予null。

final关键字

基本介绍

final可以修饰类、属性、方法和局部变量。

使用场景:

  1. 当不希望类被继承时。
  2. 当不希望父类的某个方法被子类覆盖/重写(override)时。
  3. 当不希望类的的某个属性的值被修改时。(例如: public final double TAX RATE=0.08)
  4. 当不希望某个局部变量被修改,可以使用final修饰(例如: final double TAX RATE=0.08),大写。

final修饰变量

  1. final修饰的属性又叫常量,一般用 XX_XX_XX (大写)来命名。
  2. final修饰的属性在定义时,必须赋初值,并且以后不能再修改:
    • 定义的时候
    • 在构造器中
    • 在代码块中
class AA {
    public final double TAX_RATE2 ;
    public final double TAX_RATE3 ;

    public AA() {//构造器中赋值
        System.out.println("执行构造函数");
        TAX_RATE2 = 1.1;
    }
    {//在代码块赋值
        System.out.println("执行代码块");
        TAX_RATE3 = 8.8;
    }

    public double getValue(){
        System.out.println("执行getValue");
        return 0.08;
    }
    public final double TAX_RATE = getValue();//定义时赋值
}

执行结果:

执行代码块
执行getValue
执行构造函数

注意:如果final修饰的属性是静态的,则初始化的位置只能是1. 定义时(或调用静态函数)2.在静态代码块(不能在构造器中赋值,因为构造器是在对象创建的时候才会进行赋值)

final修饰类/方法

将方法和类声明成final只有一个原因:确保他们不会在子类中改变语义(结合多态理解),有些人认为:除非由足够多的理由使用多态,否则应该将所有的方法声明成final。

  1. 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。(因为类既然不能被继承,也就相应无法被重写)。
  2. final不能修饰构造方法。
  3. final和static 往往搭配使用,效率更高,因为不会导致类加载,底层编译器做了优化处理。

抽象类

当父类的某些方法,需要声明,但是又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类。

  1. 用abstruct关键字来修饰一个类时,这个类就叫抽象类。
  2. 用abstruct关键字来修饰一个方法时,这个方法就是抽象方法。
访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体

注意:

  1. 抽象类不能被实例化。
  2. 抽象类不一定包含abstruct方法,也就是说,抽象类可以没有abstruct方法。
  3. 一旦类包含了abstract方法,则这个类必须声明为abstract。
  4. abstract只能修饰类和方法,不能修饰属性和其它的。
  5. 抽象类可以有任意成员【抽象类本质还是类】,比如: 非抽象方法构造器静态属性等等。
  6. 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法除非它自己也声明为abstract类
  7. 抽象方法不能使用private、final和 static来修饰,因为这些关键字都是和重写相违背的。

模板设计模式

package com.hspedu.abstract_.template;

abstract public class Template { //抽象类-模板设计模式
    private String name;

    public Template(String name) {
        this.name = name;
    }

    public abstract void job();//抽象方法

    public abstract String getName();

    public void calculateTime() {//实现方法,调用job方法
        //得到开始的时间
        long start = System.currentTimeMillis();
        job(); //动态绑定机制
        //得的结束的时间
        long end = System.currentTimeMillis();
        System.out.println(getName()+"任务执行时间 " + (end - start));
    }
}

接口

基本介绍

接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。

接口是更加抽象的类。抽象类里的方法可以有方法体,接口里的所有方法都没有方法体(jdk7),接口体现了程序设计的多态和高内聚低偶合的设计思想。

示例:

public interface DBInterface { //项目经理
    
    String name = "usb";
    void connect();//连接方法
    void close();//关闭连接
}

public class OracleDB implements DBInterface{

    @Override
    public void connect() {
        System.out.println("连接oracle");
    }

    @Override
    public void close() {
        System.out.println("关闭oracle");
    }
}
public class Interface03 {
    public static void main(String[] args) {

        MysqlDB mysqlDB = new MysqlDB();
        t(mysqlDB);
        OracleDB oracleDB = new OracleDB();
        t(oracleDB);
    }

    public static void t(DBInterface db) {
        System.out.println(UsbInterface.name);
        db.connect();
        db.close();
    }
}

使用细节

  1. 接口不能被实例化。
  2. 接口中所有的方法默认是public和abstruct方法,实现该方法不写public会报错。
  3. 一个普通类实现接口,必须实现所有方法;一个抽象类实现接口,可以不实现方法。
  4. 接口是java继承机制的补充,一个类可以实现多个接口
  5. 接口不能继承其它类,一个接口可以继承多个接口
  6. 与类一致,接口的修饰符只有public和默认。
  7. 接口中的属性,默认使用public static final修饰符,使用接口名.属性名访问。

继承和接口对比

当子类继承了父类,就自动的拥有父类的功能,如果子类需要扩展功能,可以通过实现接口的方式扩展。

接口是对java单继承机制的一种补充,继承和接口解决的问题不同:

  1. 继承的价值在于:解决代码的复用性和可维护性。
  2. 接口的价值在于:设计好各种规范方法,让其它类实现这些方法。
  3. 接口比继承更加灵活:继承满足is-a的关系,而接口满足has-a的关系。

接口的多态

定义接口

public interface UsbInterface { //接口
    //规定接口的相关方法,老师规定的.即规范...
    void start();
    void stop();
}
public class Camera implements UsbInterface {//实现接口,就是把接口方法实现
    public void work(){
        System.out.println("相机正在拍照");
    }
    @Override
    public void start() {
        System.out.println("相机开始工作...");
    }

    @Override
    public void stop() {
        System.out.println("相机停止工作....");
    }
}
public class Phone implements UsbInterface {

    public void call(){
        System.out.println("手机正在打电话");
    }

    @Override
    public void start() {
        System.out.println("手机开始工作...");
    }

    @Override
    public void stop() {
        System.out.println("手机停止工作.....");
    }
}
public static void main(String[] args) {
    UsbInterface[] usbs = new UsbInterface[2];
    usbs[0] = new Camera();
    usbs[1] = new Phone();
    work(usbs);
}

public static void work(UsbInterface[] usbs) {
    for (UsbInterface usb : usbs) {
        usb.start();
        if(usb instanceof Camera){
            ((Camera)usb).work();
        } else if (usb instanceof  Phone) {
            ((Phone)usb).call();
        }
        usb.stop();
    }
}

内部类

一个类的内部又完整地嵌套了另一个类地结构,被嵌套的类称为内部类,嵌套类的类称为外部类。

类的五大成员:字段(属性)、方法、构造器、代码块、内部类。内部类可以直接访问私有属性。

内部类分类

定义在外部类局部位置上(比如方法内):

  1. 局部内部类
  2. 匿名内部类

定义在外部类成员位置上:

  1. 成员内部类
  2. 静态内部类

局部内部类

  1. 不能添加访问修饰符,但是可以使用final修饰,因为局部变量也可以使用final修饰。
  2. 内部类中:直接访问外部类所有成员,包含私有成员。如果外部类成员名(属性和方法)与局部内部类的成员名重名,按照就近原则,同时,可以使用外部类名.this.成员访问。
  3. 方法体中:首先创建对象,可以访问局部内部类中的所有属性和方法,包括私有成员。
    如果内部类继承了其它类,只能根据继承体系中访问修饰符访问父类的成员。(作用域从里到外:子类,父类,类外)
public class LocalInnerClass_ {
    public static void main(String[] args) {
        Outer01_ outer01 = new Outer01_();
        outer01.f1();
    }
}

class Outer01_ {
    private int num = 10;
    private int num2 = 20;

    public void f1() {
        class Inner01 extends Outer011_{
            private int num = 10;
            protected int num2 = 20;
            public int num3 = 40;
            int num4 = 50;

            public void f1() {
                super.f1();
                System.out.println("外部类属性num:" + Outer01_.this.num + " 外部类属性num2:" + num2 + " 内部类属性num:" + num);
                Outer01_.this.f2(); // f2();
                f3();
            }
            public void f2() {
                System.out.println("内部类f2");
            }
        }
        Inner01 inner01 = new Inner01();
        inner01.f1();
        inner01.f3();//父类而非类外
//        inner01.f4();
        System.out.println(inner01.num+inner01.num2+inner01.num3+inner01.num4);
        System.out.println(/*inner01.sal+*/inner01.sal2+inner01.sal3+inner01.sal4);

    }

    public void f2() {
        System.out.println("外部类f2");
    }
    public void f3(){
        System.out.println("外部类f3");
    }

}
class Outer011_{
    private int sal = 100;
    protected int sal2 = 200;
    public int sal3 = 300;
    int sal4 = 400;
    public void f1(){
        System.out.println("Outer011_ f1");
    }
    public void f2(){
        System.out.println("Outer011_ f2");
    }
    public void f3(){
        System.out.println("Outer011_ f3");
    }
    private void f4(){
        System.out.println("Outer011_ f4");
    }
}


Outer011_ f1
外部类属性num:10 外部类属性num2:20 内部类属性num:10
外部类f2
Outer011_ f3
Outer011_ f3
120
900

匿名内部类

匿名内部类定义在方法体,匿名内部类既是一个类的定义,同时本身也是一个对象。

  1. 没有访问修饰符,继承某个对象,直接定义。
  2. 内部类中:直接访问外部类所有成员,包含私有成员。如果外部类成员名(属性和方法)与局部内部类的成员名重名,按照就近原则,同时,可以使用外部类名.this.成员访问。
  3. 方法体中:只能根据访问修饰符访问其静态类型中的成员
public class AnonymousInnerClassDetail_ {
    public static void main(String[] args) {
        Outer03_ outer03 = new Outer03_();
        outer03.f1();
    }
}

class Outer03_{
    private int num=10;
    public int num2 =20;
    public void f1(){
        Person_ person = new Person_(){
            private int num =10;
            public int num2 = 20;
            protected int num3 = 30;
            int num4 =40;

            public void f1() {
                System.out.println("外部类属性num:" + Outer03_.this.num + " 外部类属性num2:" + num2 + " 匿名内部类属性num:" + num);
                Outer03_.this.f2();
                f2();
            }
            public void f2(){
                System.out.println("内部类f2");
            }

            @Override
            public void hi() {
                f1();
                System.out.println("匿名内部类 人在打招呼");
            }
        };
        person.hi();
        person.work();
//        System.out.println(person.num+person.num2+person.num3+person.num4);
        System.out.println(/*person.sal+*/person.sal2+person.sal3+person.sal4);
//        person.f1(); //这里报错 这里可以使用静态类型理解

    }
    public void f2() {
        System.out.println("外部类f2");
    }

}

class Person_{
    private int sal = 100;
    protected int sal2 = 200;
    public int sal3 = 300;
    int sal4 = 400;
    public void hi() {
        System.out.println("Person hi()");
    }
    public void work(){
        System.out.println("人在工作");
    }
}


外部类属性num:10 外部类属性num2:20 匿名内部类属性num:10
外部类f2
内部类f2
匿名内部类 人在打招呼
人在工作
900

匿名内部类最佳实现

public class AnonymousInnerClass_ {
    public static void main(String[] args) {
        Outer02_ outer02 = new Outer02_();
        outer02.f1();

        outer02.f2(new IA_() {
            @Override
            public void cry() {
                System.out.println("匿名内部类直接传参");
            }
        });
    }
}

class Outer02_ {
    private int n = 10;
    public void f1(){
        IA_ dog = new IA_() {
            @Override
            public void cry() {
                System.out.println("小狗汪汪叫");
            }
        };
        System.out.println("匿名内部类,tiger的运行类型=" + dog.getClass());
        dog.cry();
    }
    public void f2(IA_ ia){
      ia.cry();
    }
}

interface IA_ {
    void cry();
}

匿名内部类,tiger的运行类型=class com.hspedu.innerclass.Outer02_$1
小狗汪汪叫
匿名内部类直接传参

成员内部类

  1. 可以添加访问修饰符,这里本质是一个成员。
  2. 直接访问外部类所有成员,包含私有成员。外部类成员名(属性和方法)与成员内部类的成员名重名,按照就近原则,同时,可以使用外部类名.this.成员访问。
  3. 外部类:创建对象,再访问。可以访问成员内部类中的所有属性和方法,包括私有成员。
  4. 其它外部类:得到成员内部类对象,只能根据访问修饰符访问对应成员(这时候成员内部类不能是private)。
public class MemberInnerClass01_ {
    public static void main(String[] args) {
        Outer04_ outer04 = new Outer04_();
        //1 方法中使用
        outer04.t1();
        System.out.println("===================");
        //2 返回对象
        Outer04_.Inner instance = outer04.getInstance();
        instance.f1();
        System.out.println("===================");
        //3 外部调用
        Outer04_.Inner inner = outer04.new Inner();
        inner.f1();
        System.out.println("===================");
        System.out.println(/*inner.num+*/inner.sal+inner.sal2+inner.sal3); // 除了private其它可以访问
    }
}

class Outer04_ {
    private int num = 10;
    public int num2 = 20;
    public String name = "张三";

    public class Inner {
        private int num = 30;
        public double sal =40.0;
        protected double sal2 = 50.0;
        double sal3 = 60.0;
        public void f1() {
            System.out.println("外部类属性num:" + Outer04_.this.num + " 外部类属性num2:" + num2 + " 成员内部类属性num:" + num);
        }
    }
    private void f1(){
        System.out.println("外部类f1");
    }
    public Inner getInstance(){
        return new Inner();
    }

    public void t1(){
        Inner inner = new Inner();
        inner.f1();
        System.out.println(inner.num+inner.sal+inner.sal2+inner.sal3); // 内部类中所有元素都可以访问
    }
}

外部类属性num:10 外部类属性num2:20 成员内部类属性num:30
180.0
===================
外部类属性num:10 外部类属性num2:20 成员内部类属性num:30
===================
外部类属性num:10 外部类属性num2:20 成员内部类属性num:30
===================
150.0

注意:如果有private修饰,那么在类外,无法访问成员内部类的所有成员。

静态内部类

静态内部类是定义在外部类的成员位置, 并且有static修饰

  1. 可以添加访问修饰符,这里本质是一个静态成员,在类加载时进行初始化。
  2. 直接访问外部类所有静态成员,包括私有成员,不能访问非静态成员。外部类成员名(属性和方法)与静态成员内部类的成员名重名,按照就近原则,同时可以使用外部类名.成员访问。
  3. 外部类:创建对象,再访问。可以访问静态成员内部类中的所有成员,包括私有成员。
  4. 其它外部类:创建对象,再访问。得到静态成员内部类对象,只能根据访问修饰符访问对应成员(这时候成员内部类不能是private)。
public class StaticInnerClass01_ {
    public static void main(String[] args) {
        Outer05_ outer05 = new Outer05_();
        //1 方法中使用
        outer05.t1();
        System.out.println("===================");
        //2 非静态方法返回对象
        Outer05_.Inner instance = outer05.getInstance();
        instance.f1();
        System.out.println("===================");
        //3 静态方法返回对象
        Outer05_.Inner instance2 = Outer05_.getInstance2();
        instance2.f1();
        System.out.println("===================");
        //4 外部创建
        Outer05_.Inner inner = new Outer05_.Inner();
        inner.f1();
        System.out.println("===================");
        //System.out.println(inner.num);
        System.out.println(inner.sal);
    }
}

class Outer05_ {
    private static int num = 10;
    public static int num2 = 20;
    public String name = "张三";

    public static class Inner {
        public static int num2=getNum2();
        private int num = 30;
        public double sal =40.0;
        protected double sal2 = 50.0;
        double sal3 = 60.0;
        public void f1() {
            System.out.println(num);//可以访问静态成员
            //System.out.println(name);//不可以访问非静态成员
            System.out.println("外部类属性num:" + Outer05_.num + " 外部类属性num2:" + num2 + " 静态内部类属性num:" + num);
        }
        public static int getNum2(){
            System.out.println("静态成员初始化");
            return 10;
        }
        static {
            System.out.println("静态成员内部类静态代码块");
        }
    }
    private void f1(){
        System.out.println("外部类f1");
    }
    public Inner getInstance(){
        Inner inner = new Inner();
        System.out.println(inner.hashCode());
        return inner;
    }
    public static Inner getInstance2(){
        Inner inner = new Inner();
        System.out.println(inner.hashCode());
        return inner;
    }

    public void t1(){
        Inner inner = new Inner();
        inner.f1();
        System.out.println(inner.num+inner.sal+inner.sal2+inner.sal3); // 内部类中所有元素都可以访问
    }
}


静态成员初始化
静态成员内部类静态代码块
外部类属性num:10 外部类属性num2:10 静态内部类属性num:30
180.0
===================
460141958
外部类属性num:10 外部类属性num2:10 静态内部类属性num:30
===================
1163157884
外部类属性num:10 外部类属性num2:10 静态内部类属性num:30
===================
外部类属性num:10 外部类属性num2:10 静态内部类属性num:30
===================
40.0

内部类加载时机

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值