我是灼灼,一只初学Java的大一金渐层。
向往余秀华和狄兰·托马斯的疯狂,时常沉溺于将情感以诗相寄;追逐过王尔德、王小波的文字,后陷于毛姆和斯蒂芬·金不可自拔;热爱文学的浪潮,白日梦到底却总在现实里清醒;艳羡平静又极度渴盼奔跑的力量。
欢迎与我交流鸭· QQ:1517526827;
个人博客:https://blog.csdn.net/weixin_52777510?spm=1001.2101.3001.5343
Java笔记——反射和注解
Java笔记正在连载中,欢迎来其他内容逛逛哟~
相关内容如下:
【连载1】Java笔记——基本结构与流程控制
【连载2】Java笔记——数组操作
【连载3】Java笔记——面向对象编程
【连载4】Java笔记——Java核心类
【连载5】Java笔记——异常处理
【连载6】Java笔记——反射和注解
【连载7】Java笔记——泛型
【连载8】Java笔记——集合
【连载9】MySQL学习笔记
【连载10】JDBC学习笔记
【连载11】Git和GitHub的使用笔记
笔记内容来源于廖雪峰官方网站
反射
class类
思维导图如下:
每个Class
实例指向的数据类型:
┌───────────────────────────┐
│ Class Instance │──────> String
├───────────────────────────┤
│name = "java.lang.String" │
└───────────────────────────┘
┌───────────────────────────┐
│ Class Instance │──────> Random
├───────────────────────────┤
│name = "java.util.Random" │
└───────────────────────────┘
┌───────────────────────────┐
│ Class Instance │──────> Runnable
├───────────────────────────┤
│name = "java.lang.Runnable"│
一个Class
实例包含了该class
的所有完整信息:
┌───────────────────────────┐
│ Class Instance │──────> String
├───────────────────────────┤
│name = "java.lang.String" │
├───────────────────────────┤
│package = "java.lang" │
├───────────────────────────┤
│super = "java.lang.Object" │
├───────────────────────────┤
│interface = CharSequence...│
├───────────────────────────┤
│field = value[],hash,... │
├───────────────────────────┤
│method = indexOf()... │
要从Class
实例获取获取的基本信息:
public class Main {
public static void main(String[] args) {
printClassInfo("".getClass());
printClassInfo(Runnable.class);
printClassInfo(java.time.Month.class);
printClassInfo(String[].class);
printClassInfo(int.class);
}
static void printClassInfo(Class cls) {
System.out.println("Class name: " + cls.getName());
System.out.println("Simple name: " + cls.getSimpleName());
if (cls.getPackage() != null) {
System.out.println("Package name: " + cls.getPackage().getName());
}
System.out.println("is interface: " + cls.isInterface());
System.out.println("is enum: " + cls.isEnum());
System.out.println("is array: " + cls.isArray());
System.out.println("is primitive: " + cls.isPrimitive());
}
Commons Logging总是优先使用Log4j,只有当Log4j不存在时,才使用JDK的logging–>利用了JVM的动态加载特性。大致的实现代码:
// Commons Logging优先使用Log4j:
LogFactory factory = null;
if (isClassPresent("org.apache.logging.log4j.Logger")) {
factory = createLog4j();
} else {
factory = createJdkLog();
}
boolean isClassPresent(String name) {
try {
Class.forName(name);
return true;
} catch (Exception e) {
return false;
}
}
访问字段
思维导图如下:
调用方法
思维导图如下:
代码的一个转化–>
利用反射调用方法时的多态特性就展现出来啦~
Method m = Person.class.getMethod("hello");
m.invoke(new Student());
实际上相当于:
Person p = new Student();
p.hello();
调用构造方法
思维导图如下:
Constructor对象的调用结果总是返回实例,如下:
import java.lang.reflect.Constructor; //导入包
public class Main {
public static void main(String[] args) throws Exception {
// 获取构造方法Integer(int):
Constructor cons1 = Integer.class.getConstructor(int.class//class创建的整型实例);
// 调用构造方法:
Integer n1 = (Integer) cons1.newInstance(123);//调用构造方法创建实例
System.out.println(n1);
// 获取构造方法Integer(String)
Constructor cons2 = Integer.class.getConstructor(String.class);
Integer n2 = (Integer) cons2.newInstance("456");
System.out.println(n2);
}
}
获取继承关系
思维导图如下:
获取父类的Class实例举例:
integer的父类number–>
代码:
public class Main {
public static void main(String[] args) throws Exception {
Class i = Integer.class;
Class n = i.getSuperclass();
System.out.println(n);
Class o = n.getSuperclass();
System.out.println(o);
System.out.println(o.getSuperclass());
}
}
运行结果:
class java.lang.Number
class java.lang.Object
null
动态代理
思维导图如下:
CharSequence?
CharSequence是一个接口,比较常见的String、StringBuilder、StringBuffer都实现了这个接口。
当看到一个API里面有CharSequence的时候,它也是可以被其子类代替的,一般用String代替即可。
静态代码实现接口实例化~
定义接口:
public interface Hello {
void morning(String name);
}
编写实现类:
public class HelloWorld implements Hello {
public void morning(String name) {
System.out.println("Good morning, " + name);
}
}
创建实例,转型为接口并调用:
Hello hello = new HelloWorld();//实例化类hello world,那么调用该类的方法
hello.morning("Bob");
这种方式是通常编写代码的方式;
一个最简单的动态代理实现:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
InvocationHandler handler = new InvocationHandler()//定义一个invocation handler实例,来实现接口的方法调用(他被称为代理者) {
@Override
public Object invoke(Object proxy//通过它创建代理对象//, Method method, Object[] args) throws Throwable {
System.out.println(method);
if (method.getName().equals("morning")) {
System.out.println("Good morning, " + args[0]);
}
return null//这是和object有关吗?;
}
};
Hello hello = (Hello) Proxy.newProxyInstance(
Hello.class.getClassLoader(), // 传入ClassLoader,接口类的class loader
new Class[] { Hello.class//这就是被传入的接口 }, // 传入要实现的接口,因为该接口数组需要实现,所以至少需要传入一个接口
InvocationHandler(); // 传入处理调用方法的InvocationHandler,即代理者上任代理(处理接口的方法调用)
hello.morning("Bob");
}
}
interface Hello {//定义接口实现的方法
void morning(String name);
}
强制转型在哪儿???不懂.....
把动态代理改写为静态实现类大概长这样:
public class HelloDynamicProxy//接口类 implements Hello {
InvocationHandler handler;//实例代理
public //编写方法HelloDynamicProxy(InvocationHandler handler) {
this.handler = handler;
}
//编写构造方法
public void morning(String name) {
handler.invoke//之前学过的调用方法语句(
this,
Hello.class.getMethod//利用反射中的Class实例获取实例方法("morning", String.class),
new Object[] { name });//这是在做什么???
}
注解
注解的使用
思维导图如下:
常见的注解举例:
// this is a component:
@Resource("hello")
public class Hello {
@Inject
int n;
@PostConstruct
public void hello(@Param String name) {
System.out.println(name);
}
@Override
public String toString() {
return "Hello";
}
}
注解的定义
思维导图如下:
注解的处理
思维导图如下:
方法参数注解的读取栗子–>
对于以下方法定义的注解:
public void hello(@NotNull @Range(max=5) String name, @NotNull String prefix) {
}
要读取方法参数的注解,先用反射获取Method
实例,然后读取方法参数的所有注解:
// 获取Method实例:
Method m = ...
// 获取所有参数的Annotation://被保存在一个二维数组中
Annotation[][] annos = m.getParameterAnnotations();
// 第一个参数(索引为0)的所有Annotation:
Annotation[] annosOfName = annos[0];//这儿不会增大的么???
for (Annotation anno : annosOfName) {
if (anno instanceof Range) { // @Range注解
Range r = (Range) anno;
}
if (anno instanceof NotNull) { // @NotNull注解
NotNull n = (NotNull) anno;
}
}
编写一个Person
实例的检查方法,它可以检查Person
实例的String
字段长度是否满足@Range
的定义:
void check(Person person) throws IllegalArgumentException, ReflectiveOperationException {
// 遍历所有Field:
for (Field field : person.getClass().getFields()) {
// 获取Field定义的@Range:
Range range = field.getAnnotation(Range.class);
// 如果@Range存在:
if (range != null) {
// 获取Field的值:
Object value = field.get(person);
// 如果值是String:
if (value instanceof String) {
String s = (String) value;
// 判断值是否满足@Range的min/max:
if (s.length() < range.min() || s.length() > range.max()) {
throw new IllegalArgumentException("Invalid field: " + field.getName());
}
}
}
}
}
如果对你有帮助的话不要忘记一键三连噢~
谢谢鸭~
初次编写于2021//15日;
一改于2021/1/25日。