Skip to main content

内部类

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

作用:

内部类的作用:让某个类只能让本类内部能够访问到,其他的类访问不到。

例如:
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

普通内部类

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

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;

}
}

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();
}
}

静态内部类

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("内部类-静态-打印城市");
}
}
}

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(); // 静态级别 不推荐这种方式访问

}
}

局部内部类

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

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

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一个实现类,这个实现类就是匿名局部内部类。

// 实现接口案例

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();
}
// 继承抽象类案例

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(四人组)所著的一本书《设计模式》,四个开发者根据经验定的一个技巧。

原则

设计模式原则

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

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

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

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

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

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

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

单例模式

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

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

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

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;
}
}
package com.singleLetonPart;

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

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

package com.singleLetonPart;

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

private HungrySingleLeton(){};

public static HungrySingleLeton getInstance(){
return instance;
}
}
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);
}
}