内部类、静态工厂方法

一、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 是有很大风险的,除了可能导致性能、内存方面的问题外,也经常会使得代码结构变得混乱。

类的提供方,无法控制调用者的具体行为,但是我们可以尝试使用一些方法来增大自己对类的控制力,减少调用方犯错误的机会,这也是对代码更负责的具体体现。

你可能感兴趣的:(内部类、静态工厂方法)