一、注解概述
注解是代码中对代码解释和说明,区别于注释(注释不参与运行完全是给开发者看的),注解除了解释和说明,更为重要的是可以携带数据,可以在程序运行时提取(发射)。
注解的核心使命,1.用于标识一个事物(属性 方法 类型)有特殊含义。 2.用于消灭配置文件。
二、JDK内置注解
1 @Deprecated 注解
可以修饰类、方法、变量,在java源码中被@Deprecated修饰的类、方法、变量等表示不建议使用的,可能会出现错误的,可能以后会被删除的类、方法等,如果现在使用,则在以后使用了这些类、方法的程序在更新新的JDK、jar包等就会出错,不再提供支持。
个人程序中的类、方法、变量用@Deprecated修饰同样是不希望自己和别人在以后的时间再次使用此类、方法。当编译器编译时遇到了使用@Deprecated修饰的类、方法、变量时会提示相应的警告信息。
2 @Override 注解
指明被注解的方法需要覆写超类中的方法,如果某个方法使用了该注解,却没有覆写超类中的方法(如大小写写错了,或者参数错了,或者是子类自己定义的方法),编译器就会生成一个错误。
在子类中重写父类或接口的方法,@Overide并不是必须的。但是还是建议使用这个注解,在某些情况下,假设你修改了父类的方法的名字,那么之前重写的子类方法将不再属于重写,如果没有@Overide,你将不会察觉到这个子类的方法。有了这个注解修饰,编译器则会提示你这些信息。
3 @Suppresswarnings 注解
@SuppressWarnings用来抑制编译器生成警告信息,可以修饰的元素为类,方法,方法参数,属性,局部变量。它可以达到抑制编译器编译时产生警告的目的,使用@SuppressWarnings注解,采用就近原则,比如一个方法出现警告,尽量使用@SuppressWarnings注解这个方法,而不是注解方法所在的类。所属范围越小越好,因为范围大了,不利于发现该类下其他方法的警告信息。
但是很不建议使用@SuppressWarnings注解,使用此注解,开发人员看不到编译时编译器提示的相应的警告,不能选择更好、更新的类、方法或者不能编写更规范的编码。同时后期更新JDK、jar包等源码时,使用@SuppressWarnings注解的代码可能受新的JDK、jar包代码的支持,出现错误,仍然需要修改。
@SuppressWarnings(“all”) 镇压全部警告
@SuppressWarnings(“unchecked”) 镇压未检查警告
@SuppressWarnings(“unchecked”,”deprecation”) 传递多个参数
三、元注解
用来j解释注解的注解
1. @Target
表示该注解用于什么地方,可能的值在枚举类 ElemenetType 中,包括:
- ElemenetType.CONSTRUCTOR构造器声明
- ElemenetType.FIELD 域声明
- ElemenetType.LOCAL_VARIABLE局部变量声明
- ElemenetType.METHOD方法声明
- ElemenetType.PACKAGE包声明
- ElemenetType.PARAMETER 参数声明
-
2. @Retention
表示在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy 中,包括:
RetentionPolicy.SOURCE注解将被编译器丢弃
- RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃
- RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
3. @Documented
将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。
4 .@Inherited
允许子类继承父类中的注解。
@Target( {ElementType.FIELD , ElementType.TYPE } ) 一个参数就是 value = ElemenetType.FIELD
//标识将来 @Value 可以用在哪些地方
@Retention( RetentionPolicy.RUNTIME )
四、自定义注解
4.1 语法
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface myannotation {
String value() ; //名为value时 在注解处 可以省略 value=
int age() default -1;
}
例子
//反射操作注解
import javax.swing.*;
import java.lang.annotation.*;
import java.lang.reflect.Field;
@SuppressWarnings("all")
public class fanshe2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c = Class.forName("Student_table");
Annotation[] annotation = c.getAnnotations();
for (Annotation annotation1 : annotation) {
System.out.println(annotation1);//@Table(value=Student_table)
}
Table t = (Table) c.getAnnotation(Table.class);
System.out.println(t.value()); //Student_table
Field f = c.getDeclaredField("id");
Fields an = f.getAnnotation(Fields.class);
System.out.println(an.columname()); //db_id
System.out.println(an.len()); //10
System.out.println(an.type()); //int
}
}
@Target(value = ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
String value();
}
@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fields{
String columname();
String type();
int len();
}
@Table(value = "Student_table")
class Student_table{
@Fields(columname = "db_name",type="varchar",len = 3)
private String name;
@Fields(columname = "db_age",type="int",len = 10)
private int age;
@Fields(columname = "db_id",type="int",len = 10)
private int id;
public Student_table(String name, int age, int id) {
this.name = name;
this.age = age;
this.id = id;
}
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;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
4.2 可定义成分
4.3 属性默认值
为属性给定默认值,的好处就是,使用注解的时候,不要求强制赋值,反射解析的时候可以使用默认值。
4.4 反射解析注解
五.类对象:
Class 对象 里面存的是类的所有信息
一个Class对象代表一个.class文件
5.1.获取:
**1.通过类的对象,获取类对象**<br /> Student s1 = new Student();<br /> Class c = s1.getClass();<br /> **2.通过类名来获取类对象**<br /> Class c2 = Student.class;<br /> **3.通过静态方法来获取**<br /> Class c1 = Class.forName("包名+类名");
*常用的方法:
static ClassforName(String name)返回指定类名的CLass对象<br /> getName()返回此Class对象所表示的实体类的名称<br /> getSimpleName() 返回实体类的简单名字<br /> Object newInstabce() 调用无参构造, 返回CLass 的对象的实例<br /> Class getSuperClass() 获取当前CLass对象的父类<br /> Class[] getInterfaces() 返回当前class对象的接口<br /> Constructor[] getConstructors() 返回构造器对象数组<br /> Method getMethod(String name, class..t)返回方法对象<br /> Field[] getFields() 返回cLass 对象所有公共的属性<br /> <br />获取类运行时的完整结构:<br /> Fields属性 method方法 constructor构造器 superClass父类 interfaces接口 Annotation注解 <br />类的对象:new 出来的<br /> <br />
反射:Reflection API 取得类的任何信息 并且直接操作任意对象的属性和方法
目标:理解class类 并获取Class实例,创建运行时类对象,获取运行时类的完整结构,调用运行时类的指定结构
@SuppressWarnings("all")
public class fanshe {
public static void main(String[] args) {
Class c1 = Object.class;
Class c2 = Comparable.class;
Class c3 = String[] .class;
Class c4 = String[][].class;
Class c5 = Annotation.class;
Class c6 = ElementType.class;
Class c7 = void.class;
Class c8 = Class.class;
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
//只要数组的维度是一样的 他们就是同一个Class
}
}
<br />前置需求:<br />**动态语言**:在运行运行过程中可以改变接受的语言,如引进新的函数、对象、甚至是代码都可以改变程序运行时可以改变自身结构<br /> **javascript C# PHP Python**<br />**静态语言**:<br />与动态相反** java C C++** <br /> <br />java拥有了反射机制后 Java被称为准动态语言 但同时也增加了不安全性 有利有弊<br /> <br />Class c1 = Class.forName("包名+类名");<br />Class 加载完类之后,在内存的方法区就产生了Class类型的对象,一个类只有一个Class对象这个对象就包含了完整的类的信息,我们可以通过这个对象看到类的结构:就像一面镜子,透过这个镜子看到类的结构,我们称为反射<br /> java反射机制提供的功能:<br /> 在运行时是判断任意一个对象所属类<br /> 在运行时可以构建任意一- 个类的对象<br /> 在运行是判断任意一个类所具 有的成录变量和方法<br /> 在运行时获取泛型信息<br /> 在运行时调用任意的成员变量和方法<br /> 在运行时处理注释<br /> 生成动态代理<br /> <br />**优点**:可以实现动态创建对象和编译,体现出很大的灵活性<br />**缺点**:对性能有影响、使用反射基本上就是一种解释操作, 我们可以告诉jvm,我们希望做什么并且它满足<br /> 我们的要求。这类操作总是慢于直接操作<br /> 反射的主要API:<br /> java. Lang.Class :代表一个类<br /> java. Lang. reflect . Method:代表类的方法I<br /> java. lang.reflect. Field:代表类的成员变量
import com.sun.xml.internal.bind.v2.runtime.reflect.opt.Const;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@SuppressWarnings("all")
class method{
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InstantiationException {
Class cq = Class.forName("zhuejie");
System.out.println("注解类:"+cq.getName());
Field[] fields1 = cq.getFields();//这个只能找到 公共的
for (Field field : fields1) {
System.out.println("公共的字段"+field);
}
Field[] fields = cq.getDeclaredFields();//这个能找到全部的
for (Field field:fields) {
System.out.println("全部字段"+field);
}
System.out.println("========================");
Field f1 = cq.getDeclaredField("name");
System.out.println("获取指定的字段"+f1);
System.out.println("========================");
Method[] methods1 = cq.getMethods();//公共方法 本类及其父类所有的公共方法
for (Method method : methods1) {
System.out.println("公共方法"+method);
}
Method[] methods = cq.getDeclaredMethods();
for (Method method:methods) {
System.out.println("本类的所有方法"+method);
}
Method m1 = cq.getDeclaredMethod("m3");
System.out.println("获取指定的方法:"+m1);
System.out.println("========================");
System.out.println("获取构造器");
Constructor[] constructor = cq.getConstructors();
for (Constructor cons: constructor ) {
System.out.println("公共的构造器"+cons);
}
Constructor[] constructors1 = cq.getDeclaredConstructors();
for (Constructor con1 : constructors1) {
System.out.println("所有的构造器:"+con1);
}
Constructor con3 = cq.getConstructor(String.class,String.class);
System.out.println("指定的构造器"+con3);
}
}
@SuppressWarnings("all")
class method2{
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class c1 = Class.forName("zhuejie");
System.out.println("========================");
System.out.println("通过反射构建对象");
zhuejie z = (zhuejie)c1.newInstance();//调用无参构造创建对象 , 必须要有无参构造
System.out.println(z.toString());
System.out.println("========================");
System.out.println("有参构造创建对象");
Constructor con = c1.getConstructor(String.class,String.class);
zhuejie z1 = (zhuejie) con.newInstance("yangqin","male");
System.out.println(z1);
System.out.println("========================");
System.out.println("通过反射获取指定方法");
zhuejie z2 = (zhuejie) c1.newInstance();
Method setage = c1.getDeclaredMethod("setAge", int.class);
setage.invoke(z2,12);
System.out.println(z2.getAge());
System.out.println("========================");
System.out.println("通过反射对字段赋值");
zhuejie z3 = (zhuejie)c1.newInstance();
Field field = c1.getDeclaredField("name");
field.setAccessible(true);//不能直接操作私有属性 需要关闭安全检测 设置setAccessible为true
field.set(z3,"杨钦");
System.out.println(z3.getName());
/*
* setAccessible(true)
* 方法 属性 构造器 都有此方法
* 提高反射效率 如果代码中必须使用反射,且频繁调用 则设为true
* 使原本私有化的成员 可以访问
* 反射非常影响效率
* */
}
}
@SuppressWarnings("all")
class Three_sort{
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
t1();
t2();
t3();
}
public static void t1(){
zhuejie z = new zhuejie();
long before = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
z.getAge();
}
long end = System.currentTimeMillis();
System.out.println("普通方法执行时间:"+(end-before)+"ms");
}
public static void t2() throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException {
zhuejie z1 = new zhuejie();
Class c1 = z1.getClass();
Method method = c1.getDeclaredMethod("setAge", int.class);
long before = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
method.invoke(z1,12);
}
long end = System.currentTimeMillis();
System.out.println("反射方法执行时间:"+(end-before)+"ms");
}
public static void t3() throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException {
zhuejie z2 = new zhuejie();
Class c1 = z2.getClass();
Method method = c1.getDeclaredMethod("setAge", int.class);
method.setAccessible(true);
long before = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
method.invoke(z2,18);
}
long end = System.currentTimeMillis();
System.out.println("关闭安全方法执行时间:"+(end-before)+"ms");
}
}
class zhuejie{
private String name;
private 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;
}
}
类加载机制【面试题】
2.1、类加载器
类加载器(ClassLoader),顾名思义,即加载类的东西。在我们使用一个类之前,JVM需要先将该类的字节码文件(.class文件)从磁盘、网络或其他来源加载到内存中,并对字节码进行解析生成对应的Class对象,这就是类加载器的功能。我们可以利用类加载器,实现类的动态加载。
2.2、双亲委派机制
在Java中,采用双亲委派机制来实现类的加载。那什么是双亲委派机制?在Java Doc中有这样一段描述:
The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine’s built-in class loader, called the “bootstrap class loader”, does not itself have a parent but may serve as the parent of a ClassLoader instance.
从以上描述中,我们可以总结出如下四点:
1、类的加载过程采用委托模式实现
2、每个 ClassLoader 都有一个父加载器。
3、类加载器在加载类之前会先递归的去尝试使用父加载器加载。
4、虚拟机有一个内建的启动类加载器(bootstrap ClassLoader),该加载器没有父加载器,但是可以作为其他加载器的父加载器。
根类加载器(bootstrap class loader):它用来加载 Java 的核心类,是用原生代码来实现的,并不继承自 java.lang.ClassLoader(负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类)。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。
扩展类加载器(extensions class loader):它负责加载JRE的扩展目录,lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类。由Java语言实现,ExtClassLoader的父加载器为Bootstrp loader。
系统类加载器(app class loader):被称为系统(也称为应用)类加载器,它负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性,或者CLASSPATH换将变量所指定的JAR包和类路径。程序可以通过ClassLoader的静态方法getSystemClassLoader()来获取系统类加载器。如果没有特别指定,则用户自定义的类加载器都以此类加载器作为父加载器。由Java语言实现,父类加载器为ExtClassLoader。
如果所有的类加载都都无法加载这包ClassNotFoundException
2.3、类生命周期
- 加载 : 类加载器加载字节码流
- 验证 : 验证字节码合法性
- 准备 : 分配静态资源空间
- 解析 : 引用替换(符号引用替换地址直接引用)
- 初始化:赋值
- 使用:创建对象或者访问静态属性方法
- 卸载:移除
Class cls = Class.forName("com.yq.jdbc.entity.User");
// Field[] fields = cls.getDeclaredFields();
// for (int i = 0; i < fields.length; i++) {
// System.out.println(fields[i].getType().getSimpleName()+"\t"+fields[i].getName());
// getType 会获得class java.lang.Integer
// .getType().getSimpleName() 就会获得他的简单名 Integer
// fields[i].getName() 获得字段名
// }
//
//
//
// 代理访问属性
//
// Class cls2 = Class.forName("com.yq.jdbc.entity.User");
// //获得的指定字段
// Field fd = cls2.getDeclaredField("username");
// fd.setAccessible(true);
// fd.set(cls2,"dml".toString());
// System.out.println(fd.get(cls2));