简单来说,如果一个类定义在另一个类的内部,这个类就是内部类。
使用场景:当一个类的内部,包含了一个完整的事务,且这个事务没有单独设计的必要时,就可以把这个事务设计成内部类。
成员内部类就是类中的一个普通成员,类似普通的成员变量,或成员方法。
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开始,内部类中才可以创建静态成员
静态内部类,即有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);
注意:静态内部类可以直接访问外部类的静态成员,但是无法直接访问外部类的实例成员
匿名内部类是一种特殊的局部内部类,所谓匿名是指程序员不需要为这个类声明类名。
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();
}
以下是匿名内部类编译后的class文件,可以看出,它继承了接口C,实现了C中的两个方法
匿名类的核心功能是简化代码。当匿名类中只有一个函数需要实现时,可以省略多余代码。利用lambda表达式达到匿名类的效果。
test(new D() {
@Override
public void showInfo() {
System.out.println("这是简化前的代码");
}
});
test(() -> System.out.println("这是简化后的代码"));
枚举是一种特殊的类,可以理解为,枚举在本质上是一种类。
枚举其实就是将某个类的几个常用对象都罗列出来,方便后期在项目中使用。
注意:枚举罗列出来的是该枚举的对象
。
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();
}
一般情况下,枚举被用在列举常用类型的实例上。以下是一个简单示例:
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>
泛型的最基本的作用:在编译阶段约束了所能操作的数据类型,并自动进行检查,避免了强制类型转换以及其可能出现的问题。
泛型的本质:把具体的数据类型作为参数传递给类型变量
以下是一个泛型类的简单示例,模拟了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> {
}
泛型接口与泛型类基本相似,实现该接口的类需要按照接口约定
public interface F<E> {
String getName(E e);
E getObj(Integer id);
}
有方法自己申明类型变量的方法,称之为泛型方法。
以下是泛型方法的基本语法及示例说明:
修饰符 <类型变量1,类型变量2,...> 返回值类型 方法名(参数列表...){
}
public static <T> T getName(T t){
return t;
}
如果参数中传递了泛型类型,则可以使用通配符(?)来接收。
// ArrayList 是已经定义好的类型,我们在使用是可以使用?表示能接收一些类型的ArrayList集合
public static void getName2(ArrayList<?> name){
}