20.6 获取接口和父类
getInterfaces() 获取接口,返回值是一个Class[]数组,因为Java接口可以实现多个
c.getGenericInterfaces(); 获取接口 返回值是一个Type[]数组
getSuperclass() 获取父类,返回值是一个Class,父类只能。继服务器托管网承一个
c.getGenericSuperclass(); 获取父类 返回值是Type 类 getTypeName() 获取全类名
import com.qf.entitys.Student;
import java.lang.reflect.Field;
public class Demo6 {
public static void main(String[] args) {
Class c= Student.class;
//获取接口
Class[] interfaces = c.getInterfaces();
for (Class it : interfaces) {
System.out.println(it.getSimpleName());
}
System.out.println("========================================");
//获取父类及父类中的属性
Class superclass = c.getSuperclass();
System.out.println(superclass.getSimpleName());
Field[] declaredFields = superclass.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f.getName());
}
System.out.println("============================================");
//对比,看能不能拿到父类中的属性
Field[] declaredFields1 = c.getDeclaredFields();
for (Field f : declaredFields1) {
System.out.println(f.getName());
}
}
}
获取父类的父类
public class Demo7 {
public static void main(String[] args) {
Class stu = Student.class;
Class peo = stu.getSuperclass();
Class ani = peo.getSuperclass();
System.out.println(ani.getSimpleName());
}
}
获取接口的父接口
public class Demo8 {
public static void main(String[] args) {
Class c= Student.class;
Class[] interfaces = c.getInterfaces();
for (Class it: interfaces) {
if("study".equals(it.getSimpleName().toLowerCase())){
//获取父接口,虽然接口的语法实现上使用的是extends,但是接口就是接口,所以还是要使用获取接口的方式来拿
Class[] interfaces1 = it.getInterfaces();
System.out.println(interfaces1[0].getSimpleName());
}
}
}
}
20.7 类加载器
1.类加载器概述
类加载就是将磁盘上的class文件加载到内存中。虚拟机设计团队把类加载阶段的”通过一个类的全限定名(全类名)获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为”类加载器”。类加载器是JVM执行类加载机制的前提。
ClassLoader
ClassLoader的作用 ClassLoader是Java的核心组件,所有的Class都是由ClassLoader进行加载的。 ClassLoader负责通过各种方式将Class信息的二进制数据流读入JVM内部,转换为一个于目标类对应的java.lang.Class对象实例。然后交给Java虚拟机进行链接、初始化等操作。因此,ClassLoader在整个装载阶段,只能影响到类的加载,而无法通过ClassLoader去改变类的链接和初始化行为。至于他是否可以运行,则由Execution Engine决定。
双亲委派
Student,Teacher加载这个类的时候加顺序是从上到下,从前面两个加载中找类的过程叫双亲委派。
沙箱安全
如果在前面两个类加载中找到了相同的类这时会报错,报错的机制叫沙箱安全
自己创建一个String 这时执行会引发沙箱安全,是因为String本身在Extension ClassLoader中存在一个系统的String
启动类加载器:
Bootstrap 这个类加载使用C/C++语言实现,嵌套在JVM内部
用来加载Java核心库(JAVA_HOME/jre/lib/rt.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类。
并不继承自java.lang.ClassLoader,没有所谓的父加载器
出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类
启动类加载器还用于去加载扩展类加载器和应用程序类加载器,并指定为他们的父类加载器。
扩展类加载器 ExtClassLoader
- 有Java语言编写,由sun.misc.Launcher$ExtClassLoader实现
- 继承于ClassLoader类
- 父类加载器为启动类加载器
从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录下加载类库。如果用户创建的jar放在目录下,也会自动有扩展类加载器加载。
系统类加载器 AppClassLoader
Java语言编写,由sun.misc.Launcher$AppClassLoader实现
在这层加载器,会去加载我们自己写的类,我们的程序会先编译,再执行。idea在编译的时候不单单将类文件放到classes文件中,还会把resources文件夹下的资源文件也放进去。
编译就是把.java变成.class ,执行一定是执行的.class文件。AppClassLoader 加载的.class文件到内存,在哪里去找.class文件,idea工具来讲,target–>classes文件夹中去找类,所以Demo10.class.getClassLoader().getResourceAsStream(“a.txt”);相当于直接从classes文件夹加载一个输入流。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Demo10 {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream = Demo10.class.getClassLoader().getResourceAsStream("a.txt");
BufferedReader reader=new BufferedReader(new InputStreamReader(resourceAsStream));
System.out.println(reader.readLine());
}
}
20.8 properties文件
是键–值对文件,一般创建到resources文件夹中可以通过键来取值
path=C:UserAdministratorDesktopdata
filename=datasource.bat
abc=hello
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class Main {
public static void main(String[] args) {
//创建个Properties对象
Properties properties=new Properties();
try {
//通过load方法将文件加载进Properties对象中,load方法的参数给一个inputStream,可以直接使用ClassLoader中的流
properties.load(Main.class.getClassLoader().getResourceAsStream("config.properties"));
//get("键名")获取对应的值
System.out.println(properties.get("path"));
System.out.println(properties.get("filename"));
System.out.println(properties.get("abc"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
20.9 自定义注解
注解本身并没有什么卵用,只能起文本性说明
Annotation 注解类型
注解的定义
@interface来定义注解
public @interface Target {
/**
*叫注解的属性
* 数据类型 属性名();
*/
ElementType[] value();
}
@Target(value ={ElementType.TYPE,ElementType.METHOD})
public @interface Insert {
String value() default ""; //代表为注解的属性给一个默认值
}
在使用注解的时候可以为注解的属性赋值
//当前使用target定义的这个注解可以用到类上和方法上
@Target(value ={ElementType.TYPE,ElementType.METHOD})
java 4个元注解:
@Target
是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的,注释可以用于类上,方法上,属性上,参数上等等
用ElementType 来指定
/** 类,接口(包括注解类型)或枚举的声明 */
TYPE,
/** 属性的声明 */
FIELD,
/** 方法的声明 */
METHOD,
/** 方法形式参数声明 */
PARAMETER,
/** 构造方法的声明 */
CONSTRUCTOR,
/** 局部变量声明 */
LOCAL_VARIABLE,
/** 注解类型声明 */
ANNOTATION_TYPE,
/** 包的声明 */
PACKAGE
@Retention
RetentionPolicy.RUNTIME 运行时 使用它
RetentionPolicy.CLASS 编译到class文件
RetentionPolicy.SOURCE Java源文件阶段
@Documented
是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中。在生成项目文档的时候会不会被一起生产说明书
@Inherited
是指定某个自定义注解如果写在了父类的声明部分,那么子类的声明部分也能自动拥有该注解 ,是否能被继承
通过反射获取注解
//只能看看注解名,没用
public class Demo11 {
public static void main(String[] args) {
Class c=Teacher.class;
Annotation[] annotations = c.getAnnotations();
for (Annotation a: annotations) {
System.out.println(a.annotationType().getSimpleName());
}
}
}
获取注解,读取注解中的属性值
package com.qf.annotation;
import java.lang.annotation.*;
@Target(value ={ElementType.TYPE,ElementType.METHOD})
@Retention(value= RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Insert {
String value() default "";
}
package com.qf.entitys;
import com.qf.annotation.Insert;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@Insert(value = "helloworld")
public class Teacher {
private Integer teaId;
private String teaName;
private Integer teaAge;
private String teaSex;
}
import com.qf.annotation.Insert;
import com.qf.e服务器托管网ntitys.Student;
import com.qf.entitys.Teacher;
import java.lang.annotation.Annotation;
public class Demo11 {
public static void main(String[] args) {
Class c=Teacher.class;
Insert insert =(Insert) c.getAnnotation(Insert.class);
System.out.println(insert.value());
}
}
20.10 动态代理
动态代理会根据被代理类的方法的增加而自动去进行方法的代理。
Proxy.newProxyInstance() 用于生成代理对象
参数1:代理方法类的ClassLoader()
参数2: 被代理接口的类型数组
参数3:代理方法的对象
实现InvocationHandler接口 代理接口
package com.qf.proxyentity;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class Mapper implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
//proxy 代理对象
//method 执行的目标方法
//目标方法的参数
在动态代理中注解的作用是为了区分业务逻辑。
注解类
package com.qf.annotation;
import java.lang.annotation.*;
@Target(value ={ElementType.TYPE,ElementType.METHOD})
@Retention(value= RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Insert {
String value() default "";
}
package com.qf.annotation;
import java.lang.annotation.*;
@Target(value ={ElementType.TYPE,ElementType.METHOD})
@Retention(value= RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Query {
String value() ;
}
被代理的接口,没有具体的实现类
import com.qf.entitys.Teacher;
import java.util.List;
public interface TeacherDao {
@Insert(value = "addTeacher")
public int add();
@Query(value ="querybyid" )
public Teacher query(int id);
@Insert(value = "insertString")
public int insert();
@Query(value = "queryall")
public List queryAll();
}
实现了InvocationHandler接口的具体业务执行类
package com.qf.proxyentity;
import com.qf.annotation.Insert;
import com.qf.annotation.Query;
import com.qf.entitys.Teacher;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
public class Mapper implements InvocationHandler {
@Override //代理类的对象 被代理的方法 被代理方法的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(proxy.getClass().getSimpleName());
Annotation[] annotations = method.getAnnotations();
String type=annotations[0].annotationType().getSimpleName().toLowerCase();
if("insert".equals(type)){
Insert insert= method.getAnnotation(Insert.class);
if(insert.value().equals("addTeacher")){
System.out.println("执行的是添加中的addTeacher方法");
return 2;
}else if(insert.value().equals("insertString")){
System.out.println("执行的是添加中的insertString方法");
return 3;
}
return 1;
}else if("query".equals(type)){
Query query= method.getAnnotation(Query.class);
if("querybyid".equals(query.value())){
System.out.println("执行了querybyid方法,参数是:"+args[0]);
return new Teacher(1,"张三",23,"男");
}else if("queryall".equals(query.value())){
System.out.println("执行了queryall方法");
return Arrays.asList(new Teacher(1,"张三",23,"男"),new Teacher(2,"谢兴灵",25,"男"),new Teacher(3,"冯小龙",20,"男"));
}
}
return null;
}
}
动态代理对象的创建类
package com.qf.proxyentity;
import com.qf.annotation.TeacherDao;
import java.lang.reflect.Proxy;
public class ProxyFactory {
public T createObject(){
Mapper mapper=new Mapper();
//动态代理对象 被代理类的类加载器 被代理类的类反射类型 数组 真正执行业务功能的对象
Object o = Proxy.newProxyInstance(TeacherDao.class.getClassLoader(), new Class[]{TeacherDao.class}, mapper);
return (T)o;
}
}
业务调用类
package com.qf;
import com.qf.annotation.TeacherDao;
import com.qf.entitys.Teacher;
import com.qf.proxyentity.ProxyFactory;
public class Demo13 {
public static void main(String[] args) {
ProxyFactory factory=new ProxyFactory();
TeacherDao dao = factory.createObject();
System.out.println(dao.add());
System.out.println("==================");
System.out.println(dao.query(1));
System.out.println("==================");
System.out.println(dao.insert());
System.out.println("========================");
System.out.println(dao.queryAll());
}
}
运行结果:
$Proxy0
执行的是添加中的addTeacher方法
2
==================
$Proxy0
执行了querybyid方法,参数是:1
Teacher(teaId=1, teaName=张三, teaAge=23, teaSex=男)
==================
$Proxy0
执行的是添加中的insertString方法
3
========================
$Proxy0
执行了queryall方法
[Teacher(teaId=1, teaName=张三, teaAge=23, teaSex=男), Teacher(teaId=2, teaName=谢兴灵, teaAge=25, teaSex=男), Teacher(teaId=3, teaName=冯小龙, teaAge=20, teaSex=男)]
Method.getDeclaringClass()获取当前这个方法所在类的反射对象
20.11 结语
Java基础的知识我就更新完了,谢谢大家这么久的支持,我会于10月15日开始更新MySQL的知识点.希望大家观看后能给出一些珍贵的建议.谢谢大家
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
8 月 26 日,源创会北京站在北京中关村创业大街圆满举办。本期源创会以“AI 大模型与底层技术探索”为主题,邀请到学界、业界多位讲师分享其在 AI 方面的研究成果和经验。 座无虚席的现场 感谢图灵教育、机械工业出版社、阿里云存储共送出 18 本书做奖品 感谢…