一、枚举
当需要定义一组常量时,强烈建议使用枚举类
类的对象只有有限个、且是确定的
public class enumTest {
public enum SeasonEnum {
SPRING("春天","春风又绿江南岸"),
SUMMER("夏天","映日荷花别样红"),
AUTUMN("秋天","秋水共长天一色"),
WINTER("冬天","窗含西岭千秋雪");
private final String seasonName;
private final String seasonDesc;
private SeasonEnum(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
}
public static void main(String[] args) {
SeasonEnum autumn = SeasonEnum.AUTUMN;
System.out.println(autumn.getSeasonDesc());
System.out.println("================");
//遍历 枚举类所有元素
SeasonEnum[] values = SeasonEnum.values();
for (SeasonEnum seasonEnum:values){
System.out.println(seasonEnum);
}
System.out.println("================");
//字符串转枚举对象
SeasonEnum SPRING = SeasonEnum.valueOf("SPRING");
System.out.println(SPRING.getSeasonDesc());
}
}
/*
秋水共长天一色
================
SPRING
SUMMER
AUTUMN
WINTER
================
春风又绿江南岸
*/
说明:
- 使用 enum 定义的枚举类默认继承了 java.lang.Enum类,因此不能再继承其他类
- 枚举类的构造器只能使用 private权限修饰符 防止被其他人创建对象
- 枚举类的所有实例必须在枚举类中显式列出(, 分隔 ; 结尾)。列出的实例系统会自动添加 public static final 修饰
- 必须在枚举类的第一行声明枚举类对象
二 、注解(Annotation)
注解就是代码里的特殊标记,可以在编译、类加载、运行时读取,并执行相应的处理。注解可以像修饰符一样使用,用于修饰包、类、构造器、方法、成员变量、参数等。
一定程度上:框架 = 注解 + 反射+设计模式
2.1 jdk内置的三个注解
@Override 重写父类方法
@Deprecated 标注已经过时的方法
@SuppressWarnings 抑制编译器警告 @SuppressWarnings("unuserd")
2.2 jdk的四个元注解
用于修饰其他自定义Annotation
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})//用于指定能修饰哪些元素类型 字段 方法 类
@Retention(RetentionPolicy.RUNTIME)//运行期间保留 //指明注解的生命周期 RetentionPolicy.SOURCE 编译期间丢失;RetentionPolicy.CLASS class文件期间保留
@Documented 提渠道JavaDoc文档
@Inherited 具有继承性
使用 @interface 关键字
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})//用于指定能修饰哪些元素类型 字段 方法 类
@Retention(RetentionPolicy.RUNTIME)//运行期间保留 //指明注解的生命周期 RetentionPolicy.SOURCE 编译期间丢失;RetentionPolicy.CLASS class文件期间保留
public @interface MyAnnotation {
// 成员属性 类型String 变量名value 默认值hello
String value() default "hello";
}
三、泛型
泛型 即允许在声明变量、创建对象时确认实际得参数类型。如果不使用泛型,而用Object得话,需要强转,并且可能出错。
// T表示类型。这里使用任意字母都可以
public class generics<T> {
private T testObj;
public T getTestObj() {
return testObj;
}
public void setTestObj(T testObj) {
this.testObj = testObj;
}
public static void main(String[] args) {
//一定要在类名后面指定类型参数的值 不能用基本数据类型填充。但可以使用包装类填充
generics<Float> floatTest = new generics<Float>();
generics<Boolean> booleangenerics = new generics<Boolean>();
floatTest.setTestObj(1.0f);
booleangenerics.setTestObj(true);
System.out.println(floatTest);
System.out.println(booleangenerics);
}
}
限制泛型可用类型 <T extends List> 则实现类必须是继承List
四、反射
反射机制允许在运行期间根据对象获取类得内部信息,包括属性及方法。反射的应用场景:动态性 不知道是那个类。
4.1 基本使用
public class fansheTestNew {
private String name;
public int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "fansheTestNew{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public fansheTestNew(String name, int age) {
this.name = name;
this.age = age;
}
private fansheTestNew(String name){
this.name = name;
}
public void show(){
System.out.println("无参的show方法");
}
public void show(String msg){
System.out.println(this.name+"有参的show方法"+msg);
}
public static void main(String[] args) throws Exception{
//此时 类fansheTestNew就是Class的一个实例
Class clazz = fansheTestNew.class;
//获取类的构造器
Constructor constructor = clazz.getConstructor(String.class, int.class);
Object tom = constructor.newInstance("Tom", 12);
fansheTestNew tom1 = (fansheTestNew)tom;
System.out.println(tom1.toString());
//根据名称 获取属性
Field age = clazz.getDeclaredField("age");
age.set(tom1,25);//修改tom1对象的age属性
System.out.println(tom1.toString());
//根据方法名和参数类型 获取方法
Method show = clazz.getDeclaredMethod("show", String.class);
//执行tom1对象的方法
show.invoke(tom1,"你好");
//获取类的私有结构 如私有的构造器、方法、属性
Constructor constructor1 = clazz.getDeclaredConstructor(String.class);
constructor1.setAccessible(true);
Object jerry = constructor1.newInstance("jerry");
fansheTestNew jerry1 = (fansheTestNew)jerry;
System.out.println(jerry1.toString());
//获取私有的属性
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(jerry1,"mike");
System.out.println(name);
}
}
4.2 获取Class实例的四种方式
public static void main(String[] args) throws ClassNotFoundException {
//方式一 类.class
Class<fansheTestNew> clazz1 = fansheTestNew.class;
//方式二 对象.getClass
fansheTestNew obj = new fansheTestNew("ali",12);
Class clazz2 = obj.getClass();
//方式三 全路径名
Class clazz3 = Class.forName("main.FirstDemo.zhujie.fansheTestNew");
//方式四 类的加载器
ClassLoader classLoader = obj.getClass().getClassLoader();
Class clazz4 = classLoader.loadClass("main.FirstDemo.zhujie.fansheTestNew");
System.out.println(clazz1 == clazz2 );
System.out.println(clazz1 == clazz3 );
System.out.println(clazz1 == clazz4 );
//均为true
}
类加载的作用:将class文件字节码内容加载到内存中,并将静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的Class对象,作为方法区中类数据的访问入口。一旦某个类被加载到类加载器中,它将维持加载一段时间。不过JVM垃圾回收机制可以回收这些Class对象。
4.3 加载配置文件的两种方式
public class test1 {
public static void main(String[] args) throws IOException {
Properties pro = new Properties();
//方式1 直接加载文件流 此时默认路径是module下
FileInputStream fis = new FileInputStream("service1.properties");
pro.load(fis);
ClassLoader classLoader = test1.class.getClassLoader();
// 加载方式2 直接通过反射 或者 先获得类加载器,最终都是通过类的加载器的方法
//此时默认路径是 module/src/resource下
InputStream resourceAsStream1 = test1.class.getResourceAsStream("service1.properties");
InputStream resourceAsStream = classLoader.getResourceAsStream("service1.properties");
pro.load(resourceAsStream);
System.out.println(pro.getProperty("user"));
}
}
4.4 反射获取类的信息结构
public class fansheTest2 {
public static void main(String[] args) {
Class<Person> personClass = Person.class;
//获取当前类 及其父类的public属性字段
Field[] fields = personClass.getFields();
for(Field field:fields){
System.out.println(field);
}
// 获取自身所有权限的属性字段 不包括父类的
Field[] declaredFields = personClass.getDeclaredFields();
for (Field field:declaredFields){
// 获取权限修饰符 返回数字
int modifiers = field.getModifiers();
//获取数据类型 int String
String name = field.getType().getName();
//获取变量名
String name1 = field.getName();
System.out.println(field);
}
//获取当前类及其父类的 所有public方法
Method[] methods = personClass.getMethods();
//获取当前类的所有方法 包括私有方法
Method[] declaredMethods = personClass.getDeclaredMethods();
//获取每个方法上的 所有注解
for (Method m: declaredMethods){
//获取权限修饰符
int modifiers = m.getModifiers();
// 获取方法的返回值类型
String name = m.getReturnType().getName();
//获取方法名
String name1 = m.getName();
// 获取形参列表
m.getParameters();
//只能获取 runtime的注解
Annotation[] annotations = m.getAnnotations();
for(Annotation annotation:annotations){
System.out.println(annotation);
}
}
}
}