------- android培训、java培训、期待与您交流! ----------
反射的基石-->Class类
每个类加载之后,系统会为该类生成一个对应的Class(字节码文件)对象,通过Class对象就可以访问到
JVM中的这个类。
获得Class对象的方式:
1:通过对象的getClass()方法
举例:
Person p = new Person();
Class c = p.getClass();
2:调用某个类的class属性
举例:
Class c = Person.class;
3:使用Class类的forName(String className)静态方法,该方法需要传入某个类的全限定名
举例:
Class c = Class.forName("cn.itcast.Person");
演示说明:
package cn.itcast;
/*
* Description:
* 该类测试通过3种方式得到的字节码文件对象是否是同一对象
* */
public class ClassTest {
public static void main(String[] args) throws ClassNotFoundException {
Person p = new Person();
Class c1 = p.getClass();
Class c2 = Person.class;
Class c3 = Class.forName("cn.itcast.Person");
System.out.println(c1 == c2); //true
System.out.println(c2 == c3); //true
}
}
通过结果可以看出,这三种方式得到的字节码文件对象,是同一个对象。
获取构造器的方法:
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
Constructor<?>[] getConstructors()
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的
所有公共构造方法。
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
Constructor<?>[] getDeclaredConstructors()
返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有
构造方法。
演示:
package com.itheima;
/*
* Person类仅用于演示反射的不同效果
*/
public class Person {
private String name;
int age;
public String address;
public static final sex;
public Person() {
}
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void show() {
System.out.println("show");
}
public void method(String name) {
System.out.println("show " + name);
}
private String function(String name, int age) {
return name + "***" + age + "***" + "function";
}
private void hello() {
System.out.println("hello");
}
@Override
public String toString() {
return name + "***" + age;
}
}
package com.itheima.reflect;
import java.lang.reflect.Constructor;
public class ConstructorTest {
public static void main(String[] args) throws Exception {
//创建字节码文件对象
Class c = Class.forName("com.itheima.Person");
//获取所有的公共构造方法
Constructor[] cons = c.getConstructors();
System.out.println("Person类的公有构造方法:");
//遍历
for(Constructor conItem : cons)
System.out.println(conItem);
System.out.println("*******************************************");
//获取所有的构造方法,包括私有
Constructor[] allCons = c.getDeclaredConstructors();
System.out.println("Person类的所有构造方法");
for(Constructor conItem : allCons)
System.out.println(conItem);
System.out.println("*******************************************");
//获取某一个构造方法
Constructor con = c.getDeclaredConstructor(String.class);
//setAccessible(boolean flag)方法,可以暴力访问非公有的构造方法
con.setAccessible(true);
//newInstance() 创建此 Class 对象所表示的类的一个新实例。
Object obj = con.newInstance("zhangSan");
System.out.println(obj);
}
}
运行结果:
Person类的公有构造方法:
public com.itheima.Person(java.lang.String,int)
public com.itheima.Person()
*******************************************
Person类的所有构造方法
private com.itheima.Person(java.lang.String)
public com.itheima.Person(java.lang.String,int)
public com.itheima.Person()
*******************************************
zhangSan***0
获取Class对象的Method方法:
Method getMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或
接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的
公共 member 方法。
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
Method[] getDeclaredMethods()
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有
方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
演示:
package com.itheima.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/*
* 步骤:
* 1:获取字节码文件对象
* 2:获取指定构造器,并调用newInstance()创建对象
* 3:根据方法名获取Method对象
* 4:调用方法访问该方法,如果该方法是非公有访问权限,需在访问之前调用setAccessble(boolean flag),
* 并设为true
* Object invoke(Object obj, Object... args)
* 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
* */
public class MethodTest {
public static void main(String[] args) throws Exception {
//获取字节码文件对象
Class c = Class.forName("com.itheima.Person");
//获取一个构造器,创建对象
Constructor con = c.getDeclaredConstructor(String.class, int.class);
Object obj = con.newInstance("Lisi", 24);
//获取方法名为function的私有方法
Method m1 = c.getDeclaredMethod("function", String.class, int.class);
//私有的成员要使用暴力访问
m1.setAccessible(true);
//使用invoke()方法调用字节码文件对象的方法
System.out.println(m1.invoke(obj, "WangWu", 32));
//获取方法名为method的公有方法
Method m2 = c.getMethod("method", String.class);
//调用方法
m2.invoke(obj, "ZhaoLiu");
}
}
运行结果:
WangWu***32***function
show ZhaoLiu
获取Class对象的Field的方法:
Field getField(String name)
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
Field[] getFields()
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的
所有可访问公共字段。
Field getDeclaredField(String name)
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
Field[] getDeclaredFields()
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的
所有字段。
演示:
package com.itheima.reflect;
import java.lang.reflect.Field;
/*
* 访问属性的步骤:
* 1:获取字节码文件对象
* 2:获取构造器,调用newInstance()方法创建对象
* 3:获取属性名
* 4:调用Field类的方法对属性进行操作
* a:Object get(Object obj) 返回指定对象上此 Field 表示的字段的值。
* b:void set(Object obj, Object value)
* 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
* 如果访问非公有属性时,要使用setAccessble(boolean flag)方法,设置为true
* */
public class FieldTest {
public static void main(String[] args) throws Exception {
//获取字节码文件对象
Class c = Class.forName("com.itheima.Person");
//使用Person类的无参构造器创建对象
Object obj = c.getConstructor().newInstance();
//获取所有的属性对象
Field[] fs = c.getDeclaredFields();
for(Field item : fs)
System.out.println(item);
//根据属性名,获取Field对象
Field f = c.getDeclaredField("sex");
//通过get()方法获取属性值
//f.set(obj,"女");不能改变final修饰的属性值,否则运行时引发异常
System.out.println(f.get(obj));
Field f1 = c.getDeclaredField("age");
f1.setAccessible(true);
//给指定属性设置属性值
f1.set(obj, 32);
//获取属性值
System.out.println(f1.get(obj));
}
}
运行结果:
private java.lang.String com.itheima.Person.name
int com.itheima.Person.age
public static final java.lang.String com.itheima.Person.sex
public java.lang.String com.itheima.Person.address
男
32
反射运用体现:
package com.itheima.reflect;
import java.lang.reflect.Method;
import java.util.ArrayList;
/*
* 通过反射向集合添加元素
* */
public class ArrayListDemo {
public static void main(String[] args) throws Exception {
ArrayList<String> al = new ArrayList<String>();
al.add("haha");
//al.add(3);因为指定了集合只能添加String类型的元素,所以编译失败
Class c = al.getClass();
//把add()方法可以接收的类型改为Object类型,就可以添加任意类型的元素
Method m = c.getMethod("add", Object.class);
//向集合添加整形的元素
m.invoke(al, 3);
System.out.println(al);
}
}
运行结果:[haha, 3]
使用反射操作数组:
在java.util.reflect包下还提供了一个Array类,Array对象可以代表所有的数组。程序可以通过
使用Array来动态的操作数组。
常用方法:
static Object newInstance(Class<?> componentType, int length)
创建一个具有指定的组件类型和长度的新数组。
static Object get(Object array, int index) 返回指定数组对象中索引组件的值。操作引用数据类型
static xxx getXxx(Object array, int index) 返回指定数组对象中索引组件的值。
其中xxx是各种基本数据类型。
static void set(Object array, int index, Object value)
将指定数组对象中索引组件的值设置为指定的新值。操作引用数据类型
static void setXxx(Object array, int index, xxx value)
将指定数组对象中索引组件的值设置为指定的新值。其中xxx是基本数据类型
演示:
package com.itheima.reflect;
import java.lang.reflect.Array;
public class ArrayTest {
public static void main(String[] args) {
//创建一个长度为5的String类型的数组
Object obj = Array.newInstance(String.class, 5);
//向数组添加元素
Array.set(obj, 0, "zhangSan");
Array.set(obj, 1, "liSi");
Array.set(obj, 2, "wangWu");
//调用get()方法,取出数组中的元素
Object str1 = Array.get(obj, 0);
Object str2 = Array.get(obj, 2);
System.out.println(str1);
System.out.println(str2);
}
}
运行结果:
zhangSan
wangWu
使用反射获取泛型信息:
通过指定类对应的Class对象,可以获得类中包含的Field,获得Field对象后,就可以很容易的
获取该Field的数据类型:
Class<?> a = f.getType();
但这种方式只对普通类型的Field有效。如果该Field的类型是有泛型限制的类型,则不能准确的
获得该Field的泛型参数。
为了获得Field的泛型类型,应该使用getGenericType()方法,返回值类型Type
如:Type t = f.getGenericType();
Type是Java编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、
类型变量和基本类型。
然后将Type对象强制类型准换为ParameterizedType对象,ParameterizedType代表被参数化的类型,
也就是增加了泛型限定的类型。它提供了两个方法:
getRawType():返回没有泛型信息的原始类型
getActualTypeArguments():返回泛型参数的类型。
案例体现一:
package com.itheima.generic;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Map;
public class GenericFieldTest {
private ArrayList<String> al;
private Map<String, Integer> m;
public static void main(String[] args) throws Exception {
Class c = GenericFieldTest.class;
Field f = c.getDeclaredField("al");
//直接使用getType()方法,来查看al的类型,但这种方法不能
//查看到泛型的类型
System.out.println(f.getType());
//通过getGenericType()方法,获取Field实例f的泛型类型
Type t = f.getGenericType();
//强制类型转换
ParameterizedType pt = (ParameterizedType)t;
System.out.println(pt);
//获取Map的Field对象
f = c.getDeclaredField("m");
//获取f的泛型类型
Type t1 = f.getGenericType();
//强制类型转换
pt = (ParameterizedType)t1;
Type[] arg = pt.getActualTypeArguments();
for(Type item: arg)
System.out.println(item);
}
}
运行结果:
class java.util.ArrayList
java.util.ArrayList<java.lang.String>
class java.lang.String
class java.lang.Integer
案例体现二:
package com.itheima.generic;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
public class GenericTest {
public static void main(String[] args) throws Exception
{
ArrayList<String> al = new ArrayList<String>();
Method m = GenericTest.class.getMethod("test", ArrayList.class);
Type[] t = m.getGenericParameterTypes();
ParameterizedType pt = (ParameterizedType)t[0];
System.out.println(pt.getRawType());
System.out.println(pt.getActualTypeArguments()[0]);
}
public static void test(ArrayList<String> al)
{
}
}
运行结果:
class java.util.ArrayList
class java.lang.String
反射的作用-->实现框架功能
框架和框架要解决的核心问题:
把框架比做成为装修的房子,用户需要给房子做装修。
框架与工具类的区别:
工具类被用户类调用,用户类被框架调用。因为框架先存在,无法知道要调用的类,所以
无法通过new关键字来创建对象,因此要用反射来做
案例体现:
package com.itheima.reflect;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Properties;
import com.itheima.Person;
/*
* 通过反射向集合添加元素
* 配置文件中的内容:className = java.util.HashSet
* 1:配置文件 -->创建输入流对象-->创建Properties对象-->使用load()方法
* 把文件加载到集合中-->通过getProperties()方法获取配置信息
* 2:根据获得的配置信息,并通过newInstance()方法,创建集合对象
* 3:向集合添加元素
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception {
InputStream is = new FileInputStream("config.properties");
Properties prop = new Properties();
prop.load(is);
is.close();
String className = prop.getProperty("className");
//创建集合对象
Collection coll = (Collection)Class.forName(className).newInstance();
coll.add(new Person("zhangSan", 23));
coll.add(new Person("liSi", 21));
coll.add(new Person("wangWu", 26));
coll.add(new Person("liSi", 21));
System.out.println(coll);
}
}
好处:如果想使用不同的集合来盛装元素,那么就可以不用改源码,直接改配置文件中的信息
JavaBean:
JavaBean是java的特殊类,主要用于传递数据信息,这种java类中的方法主要用于访问私有字段,
且方法名符合命名规范,JavaBean的实例对象通常称之为"值对象"。
JavaBean的应用:
1、在javaEE开发中,经常要使用javaBean,很多环境都要求按JavaBean方式操作
2、Java提供了对javaBean操作的类-->PropertyDescriptor 描述JavaBean
通过一对存储器方法导出的一个属性。
构造方法摘要
PropertyDescriptor(String propertyName, Class<?> beanClass)
通过调用 getFoo 和 setFoo 存取方法,为符合标准 Java 约定的属性构造一个
PropertyDescriptor。
常用方法:
Method getReadMethod() 获得应该用于读取属性值的方法。
Method getWriteMethod() 获得应该用于写入属性值的方法。
演示:
package com.itheima.reflect;
/*
* 创建一个JavaBean类
* */
public class Description {
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;
}
}
package com.itheima.reflect;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
/*
* 步骤:
* 1:根据属性名和所属的字节码文件对象创建PropertyDescription对象
* 2:调用PropertyDescription对象的方法,获取Method对象
* 3:通过Method对象的invoke()方法来调用字节码文件对象的方法
* */
public class BeanDemo {
public static void main(String[] args) throws Exception {
Description d = new Description();
//定义变量,保持属性名
String propName = "name";
//根据属性名和所属的字节码文件对象创建PropertyDescription对象
PropertyDescriptor pd = new PropertyDescriptor(propName, d.getClass());
//通过PropertyDescription的getReadMethod()方法,获得Method对象。
Method m = pd.getReadMethod();
//通过Method对象的invoke()方法来调用字节码文件对象的方法
System.out.println(m.invoke(d));
m = pd.getWriteMethod();
m.invoke(d, "zhangSan");
m = pd.getReadMethod();
System.out.println(m.invoke(d));
}
}
运行结果:
null
zhangSan
相关推荐
在"黑马程序员_Java基础辅导班教程课件[第01期]第13天"中,我们聚焦于Java编程语言的基础知识,这是一门面向初学者的课程,旨在帮助学员快速掌握Java开发的基本技能。第13天的课程通常会涵盖上一天(第12天)所学...
【标题】"01_黑马程序员_张孝祥_Java基础加强_课程价值与目标介绍.zip" 提供的是一门由黑马程序员机构推出的Java基础强化课程,由讲师张孝祥主讲,旨在深入讲解Java编程的基础知识并进行能力提升。 【描述】中提到...
含面向对象,异常处理和常用类,线程技术,集合框架,IO操作,网络编程,文件操作,反射机制,
以上只是Java知识体系的一部分,深入学习Java还需要掌握更多的概念和技术,如反射、注解、泛型、Lambda表达式、并发编程、Spring框架等。通过不断学习和实践,你可以成为一位出色的Java开发者。
《黑马程序员Java面试宝典》是一本专门为Java开发者准备的面试指南,包含了广泛而深入的Java技术知识,以及面试过程中可能会遇到的各种问题。这本书的完整版PDF提供了丰富的学习材料,帮助求职者提升自己的技术水平...
- **理解反射**:反射是Java的一种能力,可以在运行时动态地获取类的信息,并且创建和操作对象。 - **应用**:主要用于框架开发、动态代理、单元测试等领域。 #### 16. 对匿名内部类的理解 匿名内部类是一种特殊的...
"黑马程序员java基础试题、笔记"这个压缩包资源为Java初学者和希望加入"黑马程序员"培训课程的学员提供了丰富的学习材料。这些资源包括面试问题合集、整理的资料、Android面试题、学员入学面试总结、面试技巧、必须...
《黑马程序员面试宝典(java)2018版》是一本专门为Java开发者准备的面试指南,涵盖了大量在面试过程中可能遇到的问题和知识点。这本宝典由黑马程序员机构精心编纂,汇集了近万名学员的实际面试经验,为求职者提供了...
本教程出自知名教育机构黑马程序员,该机构以其深入浅出的教学方式和实用的案例著称。 在本教程中,你将学习到以下关键知识点: 1. **Java环境搭建**:首先,你需要了解如何下载和安装Java Development Kit (JDK)...
【Java编程基础】 ...以上是黑马Java教程知识点笔记的主要内容,涵盖了Java编程的基础到进阶知识,是学习和巩固Java技能的重要参考资料。通过深入理解和实践这些知识点,开发者可以逐步提升Java编程能力。
16. **反射机制**:反射允许在运行时动态访问和修改类的信息,是Java的高级特性,常用于插件开发、元编程等场景。 17. **泛型**:泛型引入后,可以在编译时检查类型安全,减少强制类型转换,提升代码的可读性和可...
本文将主要围绕“黑马程序员------类加载器学习注意点”展开,探讨一些关键知识点。 首先,我们需要理解类加载器的基本工作原理。在Java中,类加载过程包括加载(Loading)、验证(Verification)、准备...
《2018-2019年黑马最新版Java程序员面试宝典+题库pdf》是一份集合了近年来Java编程领域重点知识和面试常见问题的综合资源。这份资料主要针对初级Java程序员,旨在帮助他们巩固基础知识,掌握面试技巧,以便在求职...
|--aidl之结合反射获取应用缓存大小等空间占用 |--aidl调用系统service未公开的方法挂电话 |--aidl调用系统未公开的方法代码示例2 |--android dp和px之间转换 |--android INSTALL_PARSE_FAILED_MANIFEST_MALFORMED |...
黑马程序员作为知名的IT教育机构,推出的毕向东Java基础班,通过视频课程与配套源代码,提供了一个从零开始学习Java的平台。 毕向东老师的教学风格深入浅出,他所教授的Java基础课程,特别适合初学者。课程内容覆盖...
在Java编程语言中,泛型和反射是两个非常重要的特性,它们在软件开发中有着广泛的应用。本篇文章将深入探讨这两个概念以及它们在实际开发中的小运用。 首先,我们来看泛型(Generics)。泛型是在Java SE 5.0引入的...
该套视频课程作为2018年传智博客黑马程序员JavaEE49期的全套资源,不仅覆盖了JavaEE的基础理论知识,还深入介绍了多种主流框架的实际应用,并提供了丰富的实战案例。对于想要入门或提高JavaEE开发能力的学习者而言,...
在本篇“黑马程序员---注解归纳”中,我们将深入探讨注解的基本概念、类型以及它们在实际开发中的应用。 首先,注解在Java中是一种特殊的声明,以`@`符号开头,后面跟着注解的名称。它们可以应用于类、接口、方法、...
以上只是Java 基础部分的核心知识点,随着深入学习,还会涉及网络编程、反射、注解、设计模式等多个方面。在学习过程中,结合实际项目练习,将理论知识应用于实践,将有助于更好地理解和掌握Java。