当一个类的定义出现在另一个类的类体中,那么这个类叫做内部类,而这个内部类所在的类叫做外部类;
类的内容:成员变量,成员方法,构造方法,静态方法,构造块和静态代码块,内部类;
实际作用:当一个类存在的价值仅仅为某一个类单独服务时,那么就可以将这个类定义为所在服务类的内部类,这样可以隐藏该类的实现细节并且可以方便的访问外部类的私有成员而不需要提供公有的get和set方法。
普通内部类-直接将一个类的定义放在另外一个类的类体中;
静态内部类-使用static关键字修饰的内部类,隶属于类层级;
局部内部类-世界将一个类的定义放在方法体的內部时;
匿名内部类-就是指没有名字的内部类;
访问修饰符 class 外部类的类名{
访问修饰符 class 内部类的类名{
内部类的类体;
}
}
/*
*实现普通内部类的定义和使用
*/
public class NormalOuter {
private int cnt =1;
//定义普通内部类,隶属于外部类的成员并且时对象层级
public class NormalInner {
private int ia = 2;
?
public NormalInner() {
System.out.println("普通内部类的构造方法体执行到了!");
}
public void show() {
System.out.println("外部类中的变量cnt的数值为: " + cnt);
System.out.println("外部类中的变量ia的数值为: " + ia);
}
}
}
public class NormalOuterTest {
public static void main(String[] args) {
//声明对象
NormalOuter no = new NormalOuter();
NormalOuter.NormalInner ni = no.new NormalInner();
//调用show方法
ni.show();
}
}
普通内部类的使用方式
1、普通内部类和普通类一样可以定义成员变量,成员方法以及构造方法等。
2、普通内部类和普通类一样可以使用final或者absract关键字修饰;
3、普通内部类还可以使用private或protected关键字进行修饰。
4、普通内部类需要使用外部类的对象来创建对象;
5、如果内部类访问外部类与本类内部同名的成员变量或方法时,需要使用this关键字。
外部类类名.this.成员变量 可以访问外部类成员变量的值
this.成员变量 可以访问内部类成员变量的值
访问修饰符 class 外部类的类名{
访问修饰符 static class 内部类的类名{
内部类的类体;
}
}
静态内部类使用方式
1、静态内部类不能直接访问外部类的非静态成员;
2、静态内部类可以直接创建对象;
3、如果静态内部类访问外部类中与本类内同名的成员变量或方法时,需要使用类名.的方式访问。
访问修饰符 class 外部类的类名{
访问修饰符 返回值类型 成员方法名(形参列表){
class 内部类的类名{
内部类的类体;
}
}
}
局部类的使用方式
1、局部内部类只能在该方法的内部使用;
2、局部内部类可以在方法体内部直接创建对象;
3、局部内部类不能使用访问控制符和static关键字修饰符。
4、局部内部类可以使用外部的局部变量,但必须时final的。由局部内部类和局部内部变量的声明周期不同所致。
概念:回调模式是指-如果一个方法的参数时接口类型,则在调用该方法的时候,需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中所实现的方法(接口中定义的)。
public interface AnoymousInterface {
//自定义抽象方法
public abstract void show();
}
public class AnoymousInterfaceImpl implements AnoymousInterface{
@Override
public void show() {
System.out.println("这里是接口的实现类");
}
}
package com.company.com.lagou.task09;
?
public class AnoymousInterfaceTest {
//AnoymousInterfaceTest ai = new AnoymousInterfaceImpl();
//接口类型的引用指向实现类型的对象,形成了多态。
public static void test(AnoymousInterface ai) {
//编译调用父类,运行调用类的重写版本
ai.show();
}
public static void main(String[] args) {
//AnoymousInterfaceTest.test(new AnoymousInterface());//接口不能实例化
AnoymousInterfaceTest.test(new AnoymousInterfaceImpl());
}
}
开发经验分享:
当接口/类类型的引用作为方法的形参时,实参的传递方式有两种:
1、自定义类实现接口/继承类并重写方法,然后创建该类对象作为实参传递;
2、使用上述匿名内部类的语法格式得到接口/类类型的引用即可。
接口/父类类型 引用变量名 = new 接口/父类类型() {方法的重写};
public class AnoymousInterfaceTest {
//AnoymousInterfaceTest ai = new AnoymousInterfaceImpl();
//接口类型的引用指向实现类型的对象,形成了多态。
public static void test(AnoymousInterface ai) {
//编译调用父类,运行调用类的重写版本
ai.show();
}
public static void main(String[] args) {
//AnoymousInterfaceTest.test(new AnoymousInterface());//接口不能实例化
AnoymousInterfaceTest.test(new AnoymousInterfaceImpl());
System.out.println("==========================");
?
//使用匿名内部类的语法格式来得到接口类型的引用
//格式是:接口/父类类型 引用变量名 = new 接口/父类类型() {方法的重写};
AnoymousInterface ait = new AnoymousInterface() {
@Override
public void show() {
System.out.println("匿名内部类就是这么玩的!");
}
};
AnoymousInterfaceTest.test(ait);
}
?
}
public class AnoymousInterfaceTest {
//AnoymousInterfaceTest ai = new AnoymousInterfaceImpl();
//接口类型的引用指向实现类型的对象,形成了多态。
public static void test(AnoymousInterface ai) {
//编译调用父类,运行调用类的重写版本
ai.show();
}
public static void main(String[] args) {
//AnoymousInterfaceTest.test(new AnoymousInterface());//接口不能实例化
AnoymousInterfaceTest.test(new AnoymousInterfaceImpl());
System.out.println("==========================");
?
//使用匿名内部类的语法格式来得到接口类型的引用
//格式是:接口/父类类型 引用变量名 = new 接口/父类类型() {方法的重写};
AnoymousInterface ait = new AnoymousInterface() {
@Override
public void show() {
System.out.println("匿名内部类就是这么玩的!");
}
};
AnoymousInterfaceTest.test(ait);
//从java8开始提出新特性lamda表达式简化上述代码,格式为:(参数列表)-> {方法体}
AnoymousInterface ait1 = () -> System.out.println("lambda表达式就是这么简单");
AnoymousInterfaceTest.test(ait1);
}
?
}
/*
编程实现所有方向的枚举
*/
public class Direction {
private final String desc;
//2 声明本类类型的引用指向本类类型的对象
public static final Direction UP = new Direction("向上");
public static final Direction DOWN = new Direction("向下");
public static final Direction LEFT = new Direction("向左");
public static final Direction RIGHT = new Direction("向右");
//构造方法实现成员变量的初始化,更加灵活
//1\私有化构造方法,此时该构造方法只能在本类内部使用
private Direction(String desc) {
this.desc = desc;
}
//通过公有的get方法可以在本类的外部访问成员变量的数值
public String getDesc() {
return desc;
}
}
public class DirectionTest {
public static void main(String[] args) {
// Direction d1 = new Direction("向上");
// System.out.println("获取到的字符串是: " + d1.getDesc());
//
// Direction d2 = new Direction("向下");
// System.out.println("获取到的字符串是: " + d2.getDesc());
//
// Direction d3 = new Direction("向左");
// System.out.println("获取到的字符串是: " + d3.getDesc());
//
// Direction d4 = new Direction("向右");
// System.out.println("获取到的字符串是: " + d4.getDesc());
?
Direction d1 = Direction.UP;
System.out.println("获取到的字符串是: " + d1.getDesc());
Direction d2 = Direction.DOWN;
System.out.println("获取到的字符串是: " + d2.getDesc());
Direction d3 = Direction.LEFT;
System.out.println("获取到的字符串是: " + d3.getDesc());
Direction d4 = Direction.RIGHT;
System.out.println("获取到的字符串是: " + d4.getDesc());
}
}
使用public static final 表示的常量描述较为繁琐,使用enum关键字来定义枚举类型取代常量,枚举类型是从java5开始增加的一种引用数据类型。
枚举值就是当前类的类型,也就是指向本类的对象,默认使用public static final 关键字共同修饰,因此采用枚举类型.的方式调用。
/*
编程实现所有方向的枚举
枚举类型的要求要求所有枚举值必须放在枚举类型的最前面
*/
public enum DirectionEnum {
//2 声明本类类型的引用指向本类类型的对象
UP("向上"),DOWN("向下"),LEFT("向左"),RIGHT("向右");
private final String desc;
//构造方法实现成员变量的初始化,更加灵活
//1\私有化构造方法,此时该构造方法只能在本类内部使用
private DirectionEnum(String desc) {
this.desc = desc;
}
//通过公有的get方法可以在本类的外部访问成员变量的数值
public String getDesc() {
return desc;
}
}
public class DirectionTest {
public static void main(String[] args) {
//使用java5开始的枚举类型
DirectionEnum de = DirectionEnum.DOWN;
System.out.println("获取到的方向是: " + de.getDesc());
}
}
枚举类可以自定义构造方法,但是构造方法的修饰符必须是private,默认也是私有的。
public class DirectionUserTest {
public static void test1(String str) {
switch (str) {
case "向上":
System.out.println("向上");
break;
case "向下":
System.out.println("向下");
break;
case "向左":
System.out.println("向左");
break;
case "向右":
System.out.println("向右");
break;
default:
System.out.println("没有这样的方法");
}
}
?
public static void test2(DirectionEnum de) {
switch (de) {
case UP:
System.out.println("向上");
break;
case DOWN:
System.out.println("向下");
break;
case LEFT:
System.out.println("向左");
break;
case RIGHT:
System.out.println("向右");
break;
default:
System.out.println("没有这样的方法");
}
}
?
public static void main(String[] args) {
DirectionUserTest.test1(Direction.UP.getDesc());
DirectionUserTest.test1(Direction.DOWN.getDesc());
DirectionUserTest.test1(Direction.LEFT.getDesc());
DirectionUserTest.test1(Direction.RIGHT.getDesc());
?
System.out.println("====================");
DirectionUserTest.test2(DirectionEnum.DOWN);
}
}
概念和方法
所有枚举类型都继承自java.lang.Enum类,常见方法如下:
static T[] values() >返回当前枚举类中的所有对象;
String to String() >返回当前枚举类对象的名称;
int ordinal() >获取枚举对象在枚举类中的索引位置;
static T valueOf(String str) >将参数指定的字符串名转为当前枚举类的对象;
int compareTo(E o) >比较两个枚举对象在定义时的顺序;
枚举不能实现继承
枚举类实现接口的方式
枚举类实现接口后需要重写抽象方法,而重写方法的方式有两种:重写一个,或者每个对象都重写;
注解又叫标注,是从java5开始增加的一种引用数据类型。
注解本质就是代码中的特殊标记,通过这些标记可以在编译、类加载、以及运行时执行指定的处理。
注解的语法格式
访问修饰符 @interface 注解名称 {
注解成员;
}
自定义注解自动继承java.lang.annotation.Annotation接口。
1、注解体中只有成员变量没有成员方法,而注解的成员变量以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
2、如果注解只有一个参数成员,建议使用参数名为value,而类型只能时八种基本数据类型、String类型、class类型、enum类型及Annotation类型。
//若一个注解中没有任何的成员,则这样的注解叫做标记注解/标识注解
public @interface MyAnnotation {
public String value() default "123";//声明一个String类型的成员变量,名字为value
public String value2();
}
//@MyAnnotation(value = "hello", value2 = "world")
@MyAnnotation(value2 = "world")
//表示将标签贴在person类的代码中,使用注解时采用 成员变量名 = 成员参数值,....
public class Person {
private String name;
private int age;
}
元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其他的注解上面。
元注解主要有:@Retention、@Documented、@Target、@Inherited、@Repeatable
RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到JVM中,默认方式。
RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载到JVM中,所以在程序运行时可以获取到它们。
@Documented 用于指定被该注解将被javadoc工具提取成文档。
定义为@Documented 的注解必须设置Retention值为RUNTIME。
从java8开始对元注解@Target的参数类型ElementType枚举值增加了两个:
其中ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中,如:泛型。
其中ElementType.TYPE_USE表示该注解能写在使用类型的任何语句中。
预制注解就是java语言自身提供的注解,具体如下:
原文:https://www.cnblogs.com/andrew037/p/13744164.html