Skip to content

内部类

概念:一个类中又书写其他的类,包含在内的类,属于内部类

作用:

java
内部类的作用:让某个类只能让本类内部能够访问到,其他的类访问不到。
    
例如:
package com.insideClassPart;

public class Student {
    private String name;
    private int age;
    private Address address;

    // 内部类Address类,属于某个实例级别的,作为实例的属性来使用
    private class Address{ // 同时通常将内部类私有
        private String city;
        private String country;
        private String zone;
    }
}

内部类分类

内部类分类为:普通内部类(实例级别),静态内部类,局部内部类,匿名内部类。

内部类的编译后的文件名格式:外部类$.内部类.class

普通内部类

实例级别,作为实例的属性来使用,依托外部类。

java
package com.insideClassPart;

public class Student {
    public String name;
    public int age;
    public Address address;

    // 内部类Address类,属于某个实例级别的,作为实例的属性来使用
    // 普通内部类
    public class Address{ // 同时通常将内部类私有 private 修饰
        private String city;
        private String country;
        private String zone;

    }
}
java
package com.insideClassPart;

public class Test01 {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.name = "aqua";
        stu.age = 18;
        // 当内部类的修饰符为 public时
        stu.address = stu.new Address();
        // 临时new一个Student对象,再new一个内部类对象
        Student.Address address = new Student().new Address();
    }
}

静态内部类

java
package com.insideClassPart;

// 外部类
public class Pet {
    private String name;
    private int age;
    // 实例级别
    public void eat(){
        System.out.println("外部类-实例-吃饭");
    }
    // 静态方法
    public static void sleep(){
        System.out.println("外部类-静态-睡觉");
    }
    // 静态内部类
    public static class Address{
        private String country;
        private String city;

        // 实例方法
        public void printCountry(){
            // 创建外部类对象
            Pet pet = new Pet();
            // 访问外部类实例方法
            pet.eat();
            // 访问外部类属性
            pet.name = "九月";
            // 访问内部类属性
            this.city = "杭州";
            System.out.println("内部类-实例-打印国家");
            System.out.println(pet.name);
            System.out.println(city);
        }
        // 静态方法
        public static void printCity(){
            System.out.println("内部类-静态-打印城市");
        }
    }
}
java
package com.insideClassPart;

// 测试静态内部类
public class Test02 {
    public static void main(String[] args) {
        // 只要访问权限允许,可以通过类名直接访问静态内部类中方法或创建对象
        Pet.Address address = new Pet.Address();
        System.out.println("address = " + address);

        // 访问静态内部类中的方法
        address.printCountry(); // 实例级别
        Pet.Address.printCity(); // 静态级别,推荐
        // address.printCity(); // 静态级别 不推荐这种方式访问
        
    }
}

局部内部类

局部内部类,首先回顾局部变量写在方法中,则局部内部类也写在方法中。

访问范围只能在这个方法内访问到。

java
public class Outer2 {
    private String field1;
    private int field2;

    public void m1(){
        System.out.println(field1);
        System.out.println(field2);
        int a = 100;
        class Inner2{
            private String field1;
            private int field2;
            public void m2(){
                // a = 123 // 报错
                System.out.println(a);
                System.out.println("局部内部类中的m2方法");
            }

        }
        Inner2 inner2 = new Inner2();
        inner2.m2();
    }


    public static void main(String[] args) {
        Outer2 outer2 = new Outer2();
        outer2.m1();
    }

}

注意:

在局部内部类中访问外部类方法中的局部变量时,此局部变量将默认以final修饰。(可通过class文件查看)。表示在局部内部类中,只能访问外部方法中的局部变量,不能修改外部方法中的局部变量;

原因:

因为 外部类中的局部变量 将随着方法的执行完毕 出栈 而内部类对象可能不会立即被回收掉,所以在局部内部类在中 修改一个已经出栈的数据 是行不通的。

匿名内部类

没有名字的内部类;

要求:必须实现一个接口或继承一个抽象类。

抽象类或接口直接new一个实现类,这个实现类就是匿名局部内部类。

java
// 实现接口案例

package com.insideClassPart;


public class Outer2 {
    public static void main(String[] args) {
        // 直接new一个实现类,这个实现类就是匿名局部内部类
        A a = new A() {
            @Override
            public void m1() {
                System.out.println("匿名内部类 " + args); // 匿名内部类对象
            }
        };
        // 调用接口中的方法
        a.m1();

    }
}

// 接口
interface A {
    void m1();
}
java
// 继承抽象类案例

package com.insideClassPart;


public class Outer2 {
    public static void main(String[] args) {
        // 直接new一个实现类,这个实现类就是匿名局部内部类
        A a = new A() {
            @Override
            public void m1() {
                System.out.println("匿名内部类 " + args); // 匿名内部类对象
            }
        };
        // 调用接口中的方法
        a.m1();

        B b = new B() {
            @Override
            public void m2() {
                System.out.println("匿名内部类 ");
            }
        };
        // 调用抽象类中的方法
        b.m2();

        // 创建线程时,快捷方法
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类的方式实现Runnable实现类");
            }
        }).start();
    }
}

// 接口
interface A {
    void m1();
}

// 抽象类
abstract class B{
    public abstract void m2();
}

通常用于创建线程时,为了省事,通过匿名内部类直接创建接口。

设计模式

设计模式来源于一个组合GOF(四人组)所著的一本书《设计模式》,四个开发者根据经验定的一个技巧。

原则

设计模式原则

ts
1.依赖倒置原则:程序应该依赖于抽象,而非依赖于具象。写项目时,先设计父类,然后再写子类。

2.单一职责(原则):高内聚,一个类只描述一个事物,一个方法只实现一个功能。

3.接口隔离原则:接口与接口之间,相互隔离,不应该产生过多的依赖关系。

4.里式替换原则:程序中的父类可以替换为子类,实现相同或者类似的功能(多态思想)。

5.迪米特法则:高内聚思想,类中的信息应该与本类直接关联,不应该间接关联或者没有关联。
(所有类中的事物应该直接与本类关联,不应该间接关联或者没有关联,一个类中不应该有跟本类没有关系的信息属性或方法,一个类中只写与本类有关联的代码其他的代码写在其他地方,比如测试的代码就写在一个单独的文件中)

6.开闭原则:对扩展开放,对修改源代码关闭。

7.合成复用原则:接口的组合、方法的复用、继承关系、代码的重用等等。

单例模式

单例模式又分为 饿汉单例和懒汉单例。

单例模式:在内存中只允许一个当前类的实例,即可以使用单例。

懒汉单例示例:只有在调用的时候才创建对象,也可以叫作懒加载

java
package com.singleLetonPart;

public class LazySingleLeton {
    // 定义一个 私有静态 实例对象为空,先不new对象,懒汉单例
    private static LazySingleLeton instance = null;

    // 构造方法私有,才能保证内存中只有一份
    private LazySingleLeton(){}

    // 定义静态方法
    public static LazySingleLeton getInstance(){
        if (instance == null){ // 当instance为空时
            instance = new LazySingleLeton(); // 创建对象
        }
        return instance;
    }
}
javascript
package com.singleLetonPart;

public class Test01 {
    public static void main(String[] args) {
        // 创建对象
        LazySingleLeton instance = LazySingleLeton.getInstance();
        System.out.println("instance = " + instance);
    }
}

饿汉单例示例:类加载时立即就创建对象

java
package com.singleLetonPart;

public class HungrySingleLeton {
    // 上来就创建对象,饿汉单例
    private static HungrySingleLeton instance = new HungrySingleLeton();

    private HungrySingleLeton(){};

    public static HungrySingleLeton getInstance(){
        return instance;
    }
}
java
package com.singleLetonPart;

public class Test01 {
    public static void main(String[] args) {
        // 创建对象
        LazySingleLeton instance = LazySingleLeton.getInstance();
        System.out.println("instance = " + instance);

        HungrySingleLeton instance2 = HungrySingleLeton.getInstance();
        System.out.println("instance2 = " + instance2);
    }
}