JAVA 基础语法备忘录 - 枚举&反射&注解

目录

学习目标:

学习内容:

学习内容:

枚举

反射

Class 类

注解(annotation)

作用在其他注解的注解(或者说 元注解)是:

总结:


 

学习目标:

  • 掌握 Java  枚举&反射&注解 基础知识

学习内容:

  1. 枚举
  2.  反射
  3.  注解
  4. 其他补充

学习内容:

  • 枚举

枚举基本语法格式:  

enum Color{
	RED  , GREEN ,BLUE;
}

关键字为  enum ,枚举定义类似于类 ,经常用于控制传入参数范围(如 性别字段 只能为 男/女)

enum Gender {
MALE, FEMALE; // 男,女
}

引用方式为 :     Gender.MALE 

  • 反射

反射相关 的 主要参考

 概述 :

Java不是动态语言。要想实现类似的功能引入反射,实现一定的动态性。既一种 “准动态”的方式。

类在加载完后就会自动产生 Class 对象。这也是反射的基础。一个对象 通过Class才能实现反射。

使用场景:

在学习工厂模式时,根据向该类中 相关方法传参的方式,按照参数不同,产生不同的对象返回。代码如下:

package priv.mode.factory;

public class ColorFactory extends AbstractFactory {

	@Override
	public Shape getShapeFactory(String shape) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Color getColorFactory(String color) {
		// TODO Auto-generated method stub
		if(color==null){
			return null;
			}
		if(color.equals("red")){
			return new RedColor();
		}else if(color.equals("black")){
			return new BlackColor();
		}
		
		return null;
	}

}

public Color getColorFactory(String color) 

如果只有两种颜色,写一个 if 判断条件即可。但是显然,但如果有200+种颜色,这种根据String color 返回对应 对象的 方式就显得捉襟见肘了。

因此,需要有这样一种方式,可以根据传入的特定字符串,自动找出字符串对应的类(动态),之后将该类实例化返回。Java反射提供了这样一种方式。

反射的概念: 
反射是一种机制/功能,利用该机制/功能可以在程序运行过程中对类进行解剖并操
作类中的构造方法,成员方法,成员属性。

对以上代码修改:

package priv.mode.factory;

public class ColorFactory extends AbstractFactory {

	@Override
	public Shape getShapeFactory(String shape) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Color getColorFactory(String color) {
		// TODO Auto-generated method stub
		if(color==null){
			return null;
			}
		
//		Color dynamaticCorlor;
		try {
			return   (Color)Class.forName("priv.mode.factory."+color).newInstance();
			 
		} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
//		if(color.equals("RedColor")){
//			return new RedColor();
//		}else if(color.equals("BlackColor")){
//			return new BlackColor();
//		}
		
 		return null;
	}

}

显然,原有的所有的 if-else 判断都被一行反射代码代替了

    return   (Color)Class.forName("priv.mode.factory."+color).newInstance();
         

Class 类

Class 类是一个很特殊的类,是反射实现的基础

 要想解剖一个类,必须先要获取到该类的Class对象。Class对象是反射的根源。每个类只有一个Class对象,也就是说如果我们有第二条new 语句,JVM 不会再生成一个该类Class对象。

Java反射的三种格式:

  1. Class.forName(package.classname);//  e.g. JDBC 连接加载驱动类
  2. Object.getClass();  
  3. className.Class

Class可以获取包括 包名,方法,属性,注解,接口,枚举,泛型信息等。

Class其他相关API测试代码如下

package priv.practice.addtion;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import priv.practice.io.FileTransport;

public class ReflectPratice {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
		// TODO Auto-generated method stub
		 Class clazz = Class.forName("priv.practice.io.FileTransport");
//		
		 System.out.println("clazz:"+clazz+"  Modifiers: "+clazz.getModifiers());
		 System.out.println("clazz name:"+clazz.getName());
		 
		 FileTransport ft = (FileTransport) clazz.newInstance();
		 ft.getTime();
		 System.out.println("------------------------");
		 FileTransport ftByConstruct = (FileTransport)clazz.getConstructor().newInstance();
		 ftByConstruct.getTime();
		 
//		 获取包名
		 Package pkg = clazz.getPackage();
		 System.out.println("pkg:"+pkg);
		 System.out.println("ft-pkg: "+ft.getClass().getPackage());
		 System.out.println("Superclass:"+clazz.getSuperclass());
		 //获取该类的所有属性(只能获取自己的,包含公有的和私有的)
		 Field[] declaredFields = clazz.getDeclaredFields();
		 System.out.println("declaredFields:"+declaredFields[0]+"***"+declaredFields[1]);
		 //获取该类的所有构造函数
		 Method[] declaredMethods=clazz.getDeclaredMethods();
		 System.out.println("declaredMethods:"+declaredMethods[3]+"***"+declaredMethods.length);
		 //
		 
	}

}

运行结果:

clazz:class priv.practice.io.FileTransport  Modifiers: 1
clazz name:priv.practice.io.FileTransport
time : ***
------------------------
time : ***
pkg:package priv.practice.io
ft-pkg: package priv.practice.io
Superclass:class java.lang.Object
declaredFields:public java.lang.String priv.practice.io.FileTransport.param01***public java.lang.String priv.practice.io.FileTransport.param02
declaredMethods:public static void priv.practice.io.FileTransport.copyFileBase(java.lang.String,java.lang.String) throws java.io.IOException***4
 

关于 Type接口(了解)

  • 注解(annotation)

注解时比较简单的JavaSE知识点,只是由于在基础代码阶段应用的比较少。后续框架用的注解比较多。常接触的注解就是 “@Override ” 方法重写的注解了。注解分为内置和自定义的注解。

1. 了解内置的注解

Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。

作用在代码的注解是

  • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

 代码如下:

 

 

作用在其他注解的注解(或者说 元注解)是:

  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。一般使用 Runtime值。
  • @Documented - 标记这些注解是否包含在用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员。
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

从 Java 7 开始,额外添加了 3 个注解:

  • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
  • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
  • @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

2. 掌握自定义注解

自定义注解:其中每一个方法声明了一个配置参数,方法名称就是参数的名称。

以下的定义不是方法,是注解的参数的定义。 格式为 : 参数类型+参数名+();

public @interface anno {
//以下的定义不是方法,是注解的参数的定义。 参数类型+参数名+();
	int baseField();        //属性为基本数据类型
	String refField();      //属性为引用数据类型
	Gender enumField();     //属性为枚举类型
	Class e();				//Class类型
	String[] f();			//一维数组类型

}

 使用注解时给属性赋值:

@注解名(属性名=值,属性名2=值2) eg:@MyAnnotation3(i = 0,s="23") 

3. 掌握元注解

元注解的作用 是使用在自定义的注解上,为自定义的注解提供支持的。

常用的元注解
@Target :定义该注解作用在什么上面(位置),默认注解可以在任何位置. 值为: Elemen
tType 的枚举值  e.g.@Target(ElementType.METHOD)
METHOD :方法
TYPE :类 接口
FIELD :字段
CONSTRUCTOR :构造方法声明
@Retention :标识这个注解什么时候是有效的。是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。 e.g. @Retention(RetentionPolicy.RUNTIME)
SOURCE :只在源码上保留(默认)
CLASS :在源码和字节码上保留
RUNTIME :在所有的阶段都保留,包括运行时也有效
java (源码阶段) ----编译---> .class(字节码阶段) ----加载内存--> 运行(RUNTIME)

 3. 掌握注解解析  ........

  •  注解补充

@Retention 自定义的注解加载到指定的类方法上时,要在类的上面标注  @Retention(RetentionPolice.runtime)否则无法在运行中加载

注解的读取 是通过 反射 来实现的 。 

  •  Java的内存分为  堆  栈  方法区。
  • 类的加载过程为 加载(load)--链接(link)---初始化(init)
  1. 加载就是将class文件加载到内存中,转换为方法区运行的一些数据结构,生成Class对象。
  2.  链接就是将二进制的字节码文件加载到JVM中,此时进行文件信息验证,同时提前加载 static静态类型。再进行解析,既将自定义的类型替换为真实的被引用的类型。
  3. 初始化就是 JVM执行类构造器,类构造器 构造的是类的信息,不是对象的构造方法!

 

 当数组中存储类时,定义该数组类不会导致类被加载。调用类的常量也不会初始化该类因为常量是在链接阶段产生的。

  • 类加载器:引用狂神的教程:

 

 测试代码

	public static void main(String[] args) throws ClassNotFoundException {
	String classPath="priv.practice.addtion.AddtionTest";
 
		ClassLoader classLoader=ClassLoader.getSystemClassLoader();
		System.out.println("ClassLoader-系统类的加载器:"+classLoader);
		System.out.println("ClassLoader-自定义类的加载器:"+Class.forName(classPath).getClassLoader());
	
		System.out.println("ClassLoader-JDK内部类的加载器:"+Class.forName(classPath).getClassLoader());
		
	}

 运行结果为  : 

 ClassLoader-系统类的加载器:sun.misc.Launcher$AppClassLoader@73d16e93
ClassLoader-自定义类的加载器:sun.misc.Launcher$AppClassLoader@73d16e93
ClassLoader-JDK内部类的加载器:sun.misc.Launcher$AppClassLoader@73d16e93

 

  • 双亲委派

检测自定义类的来源是否已经被加载器加载过。检测安全性。

 


反射操作注解

可以通过注解和反射 来完成 类似ORM框架中 类和表结构 的映射。

在ORM框架中,Java类与数据库中的表对应,通过注解和反射,可以实现类似功能。

可以通过注解操作一个表。在类中大量使用注解,通过反射读取注解,将读取到的注解拼接成指定的 SQL 语句。

代码如下:

package priv.practice.addtion;

import java.awt.Window.Type;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;

public class ReflectOprateAnnotation {
	//反射操作注解
	
	public static void main(String[] args) throws  Exception {
		// TODO Auto-generated method stub
		Class stuClazz =Class.forName("priv.practice.addtion.Student");
		//通过反射拿到对象后,再通过反射得到注解。
		Annotation[] annotations  = stuClazz.getAnnotations();
		for(Annotation annotation :annotations){
			System.out.println("annotation is : "+annotation);
			//运行结果: @priv.practice.addtion.TableDS(value=db_student)
		}
		//获得注解的value的值
		TableDS tableDS=(TableDS)stuClazz.getAnnotation(TableDS.class);
		String valueOfTableDSAnno =tableDS.value();
		System.out.println("Annotation value is : "+valueOfTableDSAnno);
		
		//获得类的指定的注解
		Field feildName=stuClazz.getDeclaredField("name");
		//getField--> java.lang.NoSuchFieldException
		FieldDS fieldDS=feildName.getAnnotation(FieldDS.class);
		System.out.println("fieldDS-columnName is : "+fieldDS.columnName());
		System.out.println("fieldDS-type is : "+fieldDS.type());
		System.out.println("fieldDS-length is : "+fieldDS.length());
		
	}

}



@TableDS(value = "db_student")
class Student{
	@FieldDS(columnName = "db_id", length = 10, type = "int")
	private int id;
	@FieldDS(columnName = "db_age", length = 3, type = "int")
	private int age;
	    //String对应的数据库数据类型为varchar
	@FieldDS(columnName = "db_name", length = 100, type = "varchar") 
	private String name;
	//
	public Student(int id, int age, String name) {
		super();
		this.id = id;
		this.age = age;
		this.name = name;
	}
	//
	public Student() {
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + ", age=" + age + ", name=" + name + "]";
	}
	
}

//注解创建
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableDS{
	String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldDS{
	String columnName();
	String type();
	int length();
}

运行结果如下:

annotation is : @priv.practice.addtion.TableDS(value=db_student)
Annotation value is : db_student
fieldDS-columnName is : db_name
fieldDS-type is : varchar
fieldDS-length is : 100
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值