一、Java内部类的定义、如何创建内部类、内部类的分类、内部类与外部类的关系
- 非静态内部类
- 静态内部类
- 方法内部类
- 匿名内部类
[转载]https://blog.csdn.net/zhao_miao/article/details/83245816
关键字static可以修饰成员变量、方法、代码块、其实还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类,静态内部类和非静态内部类之间存在一个最大的区别,非静态内部类在编译完成之后会隐含的保存着一个引用,该引用是指向创建它的外围类,但是静态类没有。没有这个引用就意味着:
1.静态内部类的创建不需要依赖外部类可以直接创建。
2.静态内部类不可以使用任何外部类的非static类(包括属性和方法),但可以存在自己的成员变量。
Inner i = new Outer.Inner();//静态内部类
Inner i = new Outer().new Inner();//非静态内部类
//可方便访问彼此私有域,内部类直接访问外部类,外部类用内部类引用间接访问。可利用内部类实现多重继承
class Outer{
private String str ="外部类中的字符串";
class Inner{
private String inStr= "内部类中的字符串";
public void print(){
System.out.println(str);
}
}
public void fun(){
Inner in = new Inner(); //用引用间接
in.print();
System.out.println(in.inStr); //可访问私有域
}
}
二、Java静态类
[转载]https://www.cnblogs.com/Alex--Yang/p/3386863.html
应用场景:当外部类需要使用内部类,而内部类无需外部类资源,并且内部类可以单独创建(不需要依赖new Outer())的时候。
public class Outer {
private String name;
private int age;
public static class Builder {
private String name;
private int age;
public Builder(int age) {
this.age = age;
}
public Builder withName(String name) {
this.name = name;
return this;
}
public Builder withAge(int age) {
this.age = age;
return this;
}
public Outer build() { //调用外部类构造函数
return new Outer(this);
}
}
private Outer(Builder b) { //外部类构造函数
this.age = b.age;
this.name = b.name;
}
}
静态内部类调用外部类的构造函数,来构造外部类,由于静态内部类可以被单独初始化说有在外部就有以下实现:
public Outer getOuter()
{
Outer outer = new Outer.Builder(2).withName("Yang Liu").build();
return outer;
}
总结:
1.如果类的构造器或静态工厂中有多个参数,设计这样类时,最好使用Builder模式,特别是当大多数参数都是可选的时候。(在第三部分解释)
2.如果现在不能确定参数的个数,最好一开始就使用构建器即Builder模式。
三、Java 的静态工厂方法
[转载]https://www.jianshu.com/p/ceb5ec8f1174作者:腾儿飞
用一个静态方法来对外提供自身实例
优势:
1.与构造器不同的第一优势在于,可取不同的名字,而不单是类名:相同的方法名,不同的参数。
2.不用每次被调用时都用new创建新对象,如单例。
3.可以返回原返回类型的子类。里氏替换原则:所有引用基类的地方都可以透明的使用其子类的对象
可以理解为:只要有父类出现的地方,都可以使用子类来替代。而且不会出现任何错误或者异常。但是反过来却不行。子类出现的地方,不能使用父类来替代。
//演示
class Person{
public static Person getInstance() {
return new Person();
//return new Player();
//return new Student();
}
}
class Player extends Person{}
class Student extends Person{}
4.可以有多个参数相同但名称不同的工厂方法:不同于构造函数,函数名相同,参数不同。
class Student{
int age;
int weight;
public Student(int age) {
this.age = age;
}
/* public Student(int weight) { //Java函数签名忽略参数名,因此两个构造方法不构成重载,报错。
this.weight = weight;
}*/
}
class Student{
int age;
int weight;
public Student() {}
public Student(int age) {this.age = age;}
//public Student(int weight) {this.weight = weight;}
public static Student instanceWithAge(int age) {
Student s = new Student();
s.age = age;
return s;
}
public static Student instanceWithWeight(int weight) {
Student s = new Student();
s.weight = weight;
return s;
}
}
5.可以减少对外暴露的属性
防止构造函数传入错误的参数。
只允许三种game,选择不同带有提示信息名字的静态工厂方法,可安全地返回实例。
class Player{
private static final String GAME1 = "Baseball";
private static final String GAME2 = "Basketball";
private static final String GAME3 = "Soccer";
String game = "";
private Player(String game) {this.game = game;}
//防止外部传入上三种game之外的参数
public static Player instanceBaseball() {return new Player(GAME1);}
public static Player instanceBasketball() {return new Player(GAME2);}
public static Player instanceSoccer() {return new Player(GAME3);}
}
6.多层控制,方便修改
将set放进方法中。
7.总结:
『考虑使用静态工厂方法代替构造器』这点,除了有名字、可以用子类等这些语法层面上的优势之外,更多的是在工程学上的意义,实质上的最主要作用是:能够增大类的提供者对自己所提供的类的控制力。
调用方使用别人提供的类时,如果要使用 new 关键字来为其创建一个类实例,如果对类不是特别熟悉,那么一定是要特别慎重的 —— new 实在是太好用了,以致于它经常被滥用,随时随地的 new 是有很大风险的,除了可能导致性能、内存方面的问题外,也经常会使得代码结构变得混乱。
类的提供方,无法控制调用者的具体行为,但是我们可以尝试使用一些方法来增大自己对类的控制力,减少调用方犯错误的机会,这也是对代码更负责的具体体现。