Java从入门到精通(五)· 内部类,枚举,泛型

Java从入门到精通(五)· 内部类,枚举,泛型

一 内部类

1.概述

简单来说,如果一个类定义在另一个类的内部,这个类就是内部类。

使用场景:当一个类的内部,包含了一个完整的事务,且这个事务没有单独设计的必要时,就可以把这个事务设计成内部类。

2.成员内部类

成员内部类就是类中的一个普通成员,类似普通的成员变量,或成员方法。

public class Outer {
    private String name;
    public class Inner{
        public void getName(){
            //内部类可以直接访问外部类的成员变量
            System.out.println(name);
            System.out.println("内部类可以直接访问外部类的成员变量");
        }
    }
}

成员内部类创建对象时,需要先创建外部类的对象。因为成员内部类包含在外部类里。

Outer.Inner inner=new Outer().new Inner();
inner.getName();

注意:从JDK16开始,内部类中才可以创建静态成员

3.静态内部类

静态内部类,即有static修饰的内部类,属于外部类自己持有

@Data
public class Outer {
    private String name;
    private Inner inner;
    public static class Inner{
        public void getName(){
            Outer outer=new Outer();
            System.out.println(outer.getName());
            System.out.println("静态内部类中访问外部类对象,需要创建对象");
        }
    }
}

以下是静态内部类创建对象的语法:

Outer outer=new Outer();
Outer.Inner inner=new Outer.Inner();
outer.setInner(inner);

注意:静态内部类可以直接访问外部类的静态成员,但是无法直接访问外部类的实例成员

4.匿名内部类

匿名内部类是一种特殊的局部内部类,所谓匿名是指程序员不需要为这个类声明类名。

new 类或接口(参数值...){
   类体(一般是方法重写)
}

以下为匿名内部类示例:

创建一个接口,声明两个方法

public interface C {
    String getName();
    void showInfo();
}

在调用接口时实现接口中的方法

public static void main(String[] args) {
    C c=new C() {
        @Override
        public String getName() {
            return "shawn";
        }
        @Override
        public void showInfo() {
            System.out.println("这是匿名内部类");
        }
    };
    c.getName();
    c.showInfo();
}

Java从入门到精通(五)· 内部类,枚举,泛型_第1张图片

以下是匿名内部类编译后的class文件,可以看出,它继承了接口C,实现了C中的两个方法

匿名类的核心功能是简化代码。当匿名类中只有一个函数需要实现时,可以省略多余代码。利用lambda表达式达到匿名类的效果。

test(new D() {
    @Override
    public void showInfo() {
        System.out.println("这是简化前的代码");
    }
});
 test(() -> System.out.println("这是简化后的代码"));

二 枚举(Enum)

1.枚举概述

枚举是一种特殊的类,可以理解为,枚举在本质上是一种类。

枚举其实就是将某个类的几个常用对象都罗列出来,方便后期在项目中使用。

注意:枚举罗列出来的是该枚举的对象

public enum AEnum {
    成员1,成员2,
    //.其他成员
}

枚举中的其他成员,包含构造器,成员方法,成员变量

  • 枚举类的构造器都是私有的(默认且只能私有),因此枚举类对外不能创建对象
  • 枚举都是最终类,不可以被继承
  • 枚举类中,从第二行开始,可以定义类的其他各种成员
  • 编译器为枚举类新增了几个方法,并且枚举都是集成自 java.lang.Enum 类的。

抽象枚举罗列对象:

1.创建抽象方法

2.使用枚举对象的构造函数实现构造方法

public enum BEnum {
    X(){
        @Override
        public void go() {
            System.out.println("抽象枚举罗列对象-X对象");
        }
    },
    Y(){
        @Override
        public void go() {
            System.out.println("抽象枚举罗列对象-Y对象");
        }
    };
    public abstract void go();
}

2.枚举的使用

一般情况下,枚举被用在列举常用类型的实例上。以下是一个简单示例:

public enum CEnum {(1),(2),其他(3);

    public Integer getValue() {
        return value;
    }
    Integer value;
    CEnum(Integer num){
        this.value=num;
    }
}

想要获取枚举对象的具体值,则可以使用以下写法:

Integer value = CEnum..getValue();
System.out.println(value);

以下是枚举的常见使用场景

public static void main(String[] args) {
    check(CEnum.);
}

static void check(CEnum c){
    switch (c){
        case:
            System.out.println("OK");
        case:
            System.out.println("fail");
        case 其他:
            System.out.println("haha");
        default:
            System.out.println("找不到");
    }
}

三 泛型

在定义类,接口,方法时,同时声明了一个类型变量,这种称之为泛型类,泛型接口,泛型方法,一般将他们统称为泛型。

声明语法:

[访问修饰符] [/接口/方法]<E>

泛型的最基本的作用:在编译阶段约束了所能操作的数据类型,并自动进行检查,避免了强制类型转换以及其可能出现的问题。

泛型的本质:把具体的数据类型作为参数传递给类型变量

1.泛型类

以下是一个泛型类的简单示例,模拟了ArrayList存取元素的基本过程:

public class MyArrayList<E> {
    private Object[] arr=new Object[10];
    private Integer size=0;
    //定义一个参数类型为泛型的方法
    public Boolean add(E e){
        if(size<arr.length){
            arr[size++]=e;
            return true;
        }else{
            return false;
        }
    }
    //定义一个返回值为泛型的方法
    public E getInfo(Integer index){
        if(index>=0 && index<arr.length){
            return (E) arr[index];
        }else{
            return null;
        }
    }
}

以下是含有两个泛型类型的泛型类:

public class MyClassTwo<E,K> {
    public Integer get(E e,K k){
        System.out.println("这里使用了两个泛型变量");
        return 1;
    }
}

以下是一个限制了泛型类型必须是某一个类或该类的子类的限定:

public class Teacher<E extends People> {
}

2.泛型接口

泛型接口与泛型类基本相似,实现该接口的类需要按照接口约定

public interface F<E> {
    String getName(E e);
    E getObj(Integer id);
}

3.泛型方法

有方法自己申明类型变量的方法,称之为泛型方法。

以下是泛型方法的基本语法及示例说明:

修饰符 <类型变量1,类型变量2,...> 返回值类型 方法名(参数列表...{

}
public static <T> T getName(T t){
    return t;
}

如果参数中传递了泛型类型,则可以使用通配符(?)来接收。

// ArrayList 是已经定义好的类型,我们在使用是可以使用?表示能接收一些类型的ArrayList集合
public static void getName2(ArrayList<?> name){
}

4.泛型的上下限

  • 上限:? extends ClassName:能接受的类必须是 ClassName 或它的子类
  • 下限:? superClassName:能接受的类必须是 ClassName 或它的父类

5.泛型擦除和基本数据类型的问题

  • 泛型是工作在编译阶段的,一旦程序编译成class文件,class中就不存在泛型类型了。这叫做泛型擦除
  • 泛型类型不支持基本数据类型,只支持引用类型,使用基本类型时需要换成对应的包装类

你可能感兴趣的:(Java,java)