Java 基础知识

编程入门 行业动态 更新时间:2024-10-25 04:27:15

Java <a href=https://www.elefans.com/category/jswz/34/1769428.html style=基础知识"/>

Java 基础知识

反射在Java编程中是很常用的功能,开发和阅读源码时,总能看到反射的身影。这里要强调一下,Java的反射真的很简单很简单,很多人以为Java的反射是一个很高深的知识点,一直不敢去触碰,以至于成为很多程序员的短板。接下来就一起来看看这个简单了一逼的反射机制

Java的反射

反射概述

Java的反射是 在运行状态中 ,对于任何一个,都能知道它的所有属性方法;对于任何一个对象,都能调用它的所有属性方法。这种能够 动态获取类的信息动态调用对象的方法 的特性就是Java的反射机制

简单的说反射就是:动态获取类的信息 和 动态调用对象的方法(或属性)

反射的关键:获取代表字节码文件(.class文件)的Class对象

注: .java 文件通过编译最终生成 .class 文件
注: Class对象代表着 .class(字节码文件) [ 当然要先得到Class对象 ]

类加载简单示例

先简单了解一下类的加载过程

Java编译器会将 .java 文件编译成 .class 文件

1.当程序执行 new User() 时,JVM会查找并加载 User.class 到内存中

2.Jvm 将 .class 加载到内存,自动创建一个Class对象。 Class对象由JVM创建,有且仅有一个,第二次 new User() 不再产生新的 Class 对象

3.一个类对应一个Class对象

反射的本质就是:得到 Class 对象后,反向获取 User 类的各种信息。比如:构造方法,成员变量,方法等

接下来就看看如何使用 Class 对象获取到 User 类的各种信息

Java反射基础API使用

首先,创建一个 User 类

public class User {}

这个类本身没有什么意义,用于演示反射示例

1.获取Class对象的方式

1.通过 Object 的 getClass()

Object 类中存在 getClass() 方法,所有对象继承自 Object 因此可以使用 Object 的 getClass() 方法获取 Class 对象

2.通过任意类的“静态”class属性 例如:User.class

3.通过Class类的静态方法 Class.forName(String name)

    public static void main(String args[]) {//1.使用Object 的 getClass() 方式获取 Class 对象User user = new User();Class uClass1 = user.getClass();System.out.println("type1:" + uClass1.getName());//2.使用任意类的"静态"class 属性Class uClass2 = User.class;System.out.println("type2:" + uClass2.getName());//3.使用Class静态方法 Class.try {Class uClass3 = Class.forName("demo.reflex.User");//参数是包括包名的完整路径System.out.println("type3:" + uClass3.getName());} catch (ClassNotFoundException e) {e.printStackTrace();}}

结果:

type1:demo.reflex.User
type2:demo.reflex.User
type3:demo.reflex.User

注意:运行期间,只有一个Class对象存在

以上几种方式都可以获取Class对象。第一个种能获取到对象了,一般就不需要使用反射;第二种需要导入包,依赖性太强;第三种较为常用,也比较符合反射的场景,根据一个完整的类名获取Class对象

2.通过反射获取类构造函数 Constructor

User 类

public class User {User(char ch) {System.out.println("默认 构造方法 ch:" + ch);}public User() {System.out.println("public 构造方法 无参");}public User(String name) {System.out.println("public 构造方法 name:" + name);}public User(String name, int age) {System.out.println("public 构造方法 name:" + name + " age:" + age);}protected User(int age) {System.out.println("protected 构造方法 age:" + age);}private User(boolean flag) {System.out.println("private 构造方法 flag:" + flag);}}

User 类构造方法,包括了 public , private , protected , 默认 类型的构造方法

测试使用

    public static void main(String args[]) throws Exception {//获取ClassClass cls = Class.forName("demo.reflex.User");System.out.println("-------获取所有公共的构造方法---------");Constructor[] consArray = cls.getConstructors();for (int i = 0; i < consArray.length; i++) {System.out.println(consArray[i]);}System.out.println("-------获取所有的构造方法 包括:public,private,protected,默认类型---------");consArray = cls.getDeclaredConstructors();for (int i = 0; i < consArray.length; i++) {System.out.println(consArray[i]);}System.out.println("-------获取 无参 构造方法并调用---------");Constructor cons = cls.getConstructor();System.out.println(cons);cons.newInstance();System.out.println("-------获取 private 构造方法并调用---------");cons = cls.getDeclaredConstructor(boolean.class);System.out.println(cons);cons.setAccessible(true);//暴力访问(忽略访问修饰符)cons.newInstance(true);}

结果输出

-------获取所有公共的构造方法---------
public demo.reflex.User(java.lang.String,int)
public demo.reflex.User(java.lang.String)
public demo.reflex.User()
-------获取所有的构造方法 包括:public,private,protected,默认类型---------
private demo.reflex.User(boolean)
protected demo.reflex.User(int)
public demo.reflex.User(java.lang.String,int)
public demo.reflex.User(java.lang.String)
public demo.reflex.User()
demo.reflex.User(char)
-------获取 无参 构造方法并调用---------
public demo.reflex.User()
public 构造方法 无参
-------获取 private 构造方法并调用---------
private demo.reflex.User(boolean)
private 构造方法 flag:true

api解释

1.获取所有构造方法 返回符合要求的 列表

//获取所有"公共的"构造方法  public
public Constructor<?>[] getConstructors()//获取所有的构造方法 包括: public,private,protected,默认类型 
public Constructor<?>[] getDeclaredConstructors() 

2.获取单个构造方法 返回符合要求的 对象

//获取"公共的"构造方法   
public Constructor<T> getConstructor(Class<?>... parameterTypes)/***获取任意访问类型的构造方法  **parameterTypes:形参类型(记住是类型)  例:int.class ,String.class*/
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

3.调用构造方法

/***调用构造方法  **initargs:构造方法参数*/
public T newInstance(Object ... initargs)

newInstance() 方法属于 Constructor 类,无参构造方法参数可以 null 或者 不填; 对于调用 private 私有构造方法需要调用 cons.setAccessible(true); 表示打破限制,强制访问,否则出错

3.通过反射获取类成员变量 Field

User类

public class User {public User() {}/*成员变量*/private int age;public String name;protected String phone;boolean isVip;@Overridepublic String toString() {return "[User name=" + name + ", age=" + age + "]";}
}

测试使用

    public static void main(String args[]) throws Exception {//获取ClassClass cls = Class.forName("demo.reflex.User");System.out.println("-------获取所有公共的成员变量---------");Field[] fieldArray = cls.getFields();for (int i = 0; i < fieldArray.length; i++) {System.out.println(fieldArray[i]);}System.out.println("-------获取所有的成员变量 包括:public,private,protected,默认类型---------");fieldArray = cls.getDeclaredFields();for (int i = 0; i < fieldArray.length; i++) {System.out.println(fieldArray[i]);}System.out.println("-------获取公共属性---------");Field field = cls.getField("name");System.out.println(field);System.out.println("-------设置属性并查看值---------");//根据构造函数 .newInstance() 获取类对象Object object = cls.getConstructor().newInstance();field.set(object, "Ruffian");//验证刚刚设置的属性User user = (User) object;System.out.println("查看name属性值:" + user.name);System.out.println("-------获取私有属性---------");field = cls.getDeclaredField("age");System.out.println(field);System.out.println("-------设置私有属性并查看值---------");field.setAccessible(true);field.set(object, 18);//验证刚刚设置的属性System.out.println("查看age属性值:" + user.toString());}

结果输出:

-------获取所有公共的成员变量---------
public java.lang.String demo.reflex.User.name
-------获取所有的成员变量 包括:public,private,protected,默认类型---------
private int demo.reflex.User.age
public java.lang.String demo.reflex.User.name
protected java.lang.String demo.reflex.User.phone
boolean demo.reflex.User.isVip
-------获取公共属性---------
public java.lang.String demo.reflex.User.name
-------设置属性并查看值---------
查看name属性值:Ruffian
-------获取私有属性---------
private int demo.reflex.User.age
-------设置私有属性并查看值---------
查看age属性值:[User name=Ruffian, age=18]

api解释

1.获取所有属性 返回符合要求的 列表

//获取所有"公共的"属性  public
public Constructor<?>[] getFields()//获取所有的属性 包括: public,private,protected,默认类型 
public Constructor<?>[] getDeclaredFields() 

2.获取单个属性 返回符合要求的 对象

//获取"公共的"属性
public Field getField(String fieldName)/***获取任意访问类型的属性**fieldName:属性名称  例: name , age */
public Field getDeclaredField(String fieldName)

3.设置属性值

/***1.obj:要设置的字段所在的对象;*2.value:要为字段设置的值;*/
public void set(Object obj,Object value)

field.set(object, "Ruffian"); 表示为属性设置值: user.name=Ruffian

第一个参数:要设置的字段所在的对象
第二个参数:要为字段设置的值

至于上述示例中获取属性值的方式,是为了方便校验通过反射设置值是否成功,一般我们通过反射获取方法,得到属性值。下面看看如何通过反射获取成员方法和调用

4.通过反射获取成员方法 调用方法 Method

User类

public class User {public void showName(String name) {System.out.println("public showName()  参数name = " + name);}protected void show() {System.out.println("public show()");}void showDefault() {System.out.println(" showDefault() 默认无参方法");}private String getAge(int age) {System.out.println("private getAge() 返回值:字符串  参数:int age = " + age);return "age:" + age;}
}

使用示例

    public static void main(String args[]) throws Exception {//获取ClassClass cls = Class.forName("demo.reflex.User");System.out.println("-------获取所有方法---------");//Method[] methodArray = cls.getMethods();Method[] methodArray = cls.getDeclaredMethods();for (int i = 0; i < methodArray.length; i++) {System.out.println(methodArray[i]);}System.out.println("-------调用任意访问类型方法---------");//根据构造函数 .newInstance() 获取类对象Object object = cls.getConstructor().newInstance();Method method = cls.getDeclaredMethod("getAge", int.class);method.setAccessible(true);Object result = method.invoke(object, 18);System.out.println("方法返回值:" + result.toString());}

结果输出

-------获取所有方法---------
private java.lang.String demo.reflex.User.getAge(int)
public void demo.reflex.User.showName(java.lang.String)
protected void demo.reflex.User.show()
void demo.reflex.User.showDefault()
-------调用任意访问类型方法---------
private getAge() 返回值:字符串  参数:int age = 18
方法返回值:age:18

api解释

1.获取所有方法 返回符合要求的 列表

//获取所有"公共的"方法  public
public Method[] getMethods()//获取所有的方法 包括: public,private,protected,默认类型 
public Method[] getDeclaredMethods()

2.获取单个方法 返回符合要求的 对象

//获取"公共的"方法
public Method getMethod(String name, Class<?>... parameterTypes)/***获取任意访问类型的方法**name:方法名称  例: getAge , showName *parameterTypes:方法形参类型(记住是类型)  例:int.class ,String.class*/
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

3.调用方法

/***obj:要调用方法所在的对象*args:调用方法所需的参数*/
public native Object invoke(Object obj, Object... args)

method.invoke(object, 18); 表示调用方法: User user=new User(); user.getAge(18);

第一个参数:

要调用方法所在的对象
如果调用方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null

第二个参数:

调用方法所需的参数
调用方法所需的形参个数为 0,则所提供的 args 数组长度可以为 0 或 null

4.Method 类的一点拓展

了解一个方法可以通过: 方法名称,方法修饰符,返回类型,形参类型/个数

看下示例程序

    public static void main(String args[]) throws Exception {//获取ClassClass cls = Class.forName("demo.reflex.User");Method[] methodArray = cls.getDeclaredMethods();Method method;for (int i = 0; i < methodArray.length; i++) {method = methodArray[i];String name = method.getName();//方法名称int modifiers = method.getModifiers();//方法修饰符Class returnType = method.getReturnType();//方法返回类型Class[] parameterTypes = method.getParameterTypes();//方法参数类型数组(形参类型)System.out.println("方法名:" + name + " 修饰符:" + Modifier.toString(modifiers) + " 返回值类型:" + returnType);//方法参数(形参)for (int j = 0; j < parameterTypes.length; j++) {System.out.println("形参" + j + ":" + parameterTypes[j]);}System.out.println("");}}

运行结果:

方法名:showName 修饰符:public 返回值类型:void
形参0:class java.lang.String方法名:show 修饰符:protected 返回值类型:void方法名:showDefault 修饰符: 返回值类型:void方法名:getAge 修饰符:private 返回值类型:class java.lang.String
形参0:int
5.Java 反射的一点场景使用
5.1 反射结合配置文件使用

User类

public class User {public void show() {System.out.println("show方法被调用...");}
}

在 D 盘目录下新建一个 pro.txt 文件

className = demo.reflex.User   //类名完整路径
methodName = show              //方法名

示例代码:

    public static void main(String args[]) throws Exception {//获取ClassClass cls = Class.forName(getValue("className"));//获取方法Method method = cls.getMethod(getValue("methodName"));Object object = cls.getConstructor().newInstance();//获取对象//调用方法method.invoke(object, null);}/**** 根据key获取配置文件中 value** @param key* @return* @throws IOException*/public static String getValue(String key) throws IOException {Properties pro = new Properties();//获取配置文件的对象File file = new File("D:\\pro.txt");//获取文件FileReader in = new FileReader(file);//获取输入流pro.load(in);//将流加载到配置文件对象中in.close();return pro.getProperty(key);//返回根据key获取的value值}

输出结果:

show方法被调用...
5.2 通过反射越过泛型检查

还记得 method.invoke(Object obj, Object... args) 方法吗? 第二个参数表示:调用方法所需参数。这是一个 Object 对象,那么,嘿嘿嘿~~~

示例代码:

    public static void main(String args[]) throws Exception {ArrayList<String> list = new ArrayList<>();list.add("AAA");list.add("BBB");/*** 获取ArrayList的Class对象,反向的调用add()方法,添加数据*/Class listClass = list.getClass(); //获取Class对象//获取add()方法Method m = listClass.getMethod("add", Object.class);//调用add()方法m.invoke(list, false);m.invoke(list, 100);//遍历集合for (Object obj : list) {System.out.println(obj);}}

输出结果:

AAA
BBB
false
100

上述代码,ArrayList 指定类型 String 如果直接 list.add(100) 则会包类型错误,通过反射调用 m.invoke(obj, obj); 传入其他类型的对象,从而实现越过泛型的检查。当然这只是一个例子,实际编码中,还是需要严格按照规范去写代码

虽然,博文比较长,但是内容真的很简单,纯属无脑式的API调用,起码通过学习反射 API 的使用先了解反射的基础。这也是为什么文章开篇说反射简单了一逼,就是为了鼓舞大家有勇气面对这些知识点

由于本文都是API的简单使用,也都参考网络资料,就不一一附上连接了。

更多推荐

Java 基础知识

本文发布于:2024-03-04 16:14:35,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1709762.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:基础知识   Java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!