---------------------- 黑马程序员 Android培训、期待与您交流! ----------------------
Class类
/*
* 对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?
* class
* Class-->代表一类什么样的事物?
*
* Person p1 = new Person();
* Person p2 = new Person();
*
* Date
*
* Math
*
*
* Class cls1 = Date.class//字节码1--->获取Date数据类的字节码
* Class cls2 = Person.class//字节码2--->获取Person类的字节码
*
* //获取p1这个对象的字节码
* p1.getClass();
*
* //通过指定路径获取字节码
* Class.forName("java.lang.String");
*
* 面试题:Class.forName的作用?
* 答:它的作用是返回字节码,返回的方式有两种:
* 1.第一种是这个字节码曾经被加载过,已经待在Java虚拟机里面了,直接返回
* 2.第二种是Java虚拟机里面还没有这份字节码,则用加载器加载,
* 把加载进来的代码缓存到虚拟机里面,以后要得到这份字节码就不用加载了
*
* 如何得到各个字节码对应的实例对象( Class类型)
* 类名.class,例如,System.class
* 对象.getClass(),例如,new Date().getClass()
* Class.forName("类名"),例如,Class.forName("java.util.Date");
*
* 总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…
* isPrimitive:判断数据是否为基本数据类型:大概自己的理解。例如:132,如果是基本数据类型,那就定义一个int接收它。
* 判断基本类型的字节码是否为同一基本类型
* 基本数据类型只有那么8种而已: byte,short,int,long,float,double,char,boolean
*/public class _05_Class类概述 {
public static void main(String[]args)throws Exception{
String str = "abc";
//获取字节码
Class cls1 = str.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
System.out.println("cls1与cls2的字节码相同吗?"+(cls1==cls2));
System.out.println("cls1与cls3的字节码相同吗?"+(cls1==cls3));
//总结:获取到的String类的字节码是相同的
//判断基本类型的字节码是否为同一基本类型
//基本数据类型只有那么8种而已: byte,short,int,long,float,double,char,boolean
System.out.println("cls1获取的字节码是一个基本类型吗?"+cls1.isPrimitive());
System.out.println("int类型的字节码是一个基本类型吗?"+int.class.isPrimitive());
System.out.println("int类字节码和Integer类字节码是一个基本类型吗?"+(int.class == Integer.class));
System.out.println("int类字节码和Integer.TYPE包装类的基本类型字节码是一个基本类型吗?"+(int.class == Integer.TYPE));
System.out.println("int数组类型的字节码是一个基本类型吗?"+int[].class.isPrimitive());
System.out.println("一个int[]类型的数组,是一个数组文件吗?"+int[].class.isArray());
}
}
反射
lConstructor类
* Constructor的两个步骤(记住)
* 1. 获取方法(获取参数类型的字节码) :指定参数类型
* Constructor constructor = String.class.getConstructor(StringBuffer.class);
* 2. 调用方法:newInstance实例化,并指定参数类型的具体参数:如向StringBuffer中添加参数
* String str = (String)constructor.newInstance(new StringBuffer("abc"));
* ----------------------------------------------------------------------------
* 记住::::反射会导致程序性能严重下降
* ----------------------------------------------------------------------------
* Class.newInstance方法与constructor.newInstance构造方法的区别?
* Class.newInstance方法并不影响Java开发和应用,但是为什么提供这个方法呢?
* 是提供一个便利,我们创建对象步骤是:class-->constructor--new Object
* Constructor constructor = String.class.getConstructor(StringBuffer.class);
*
* 它帮我们将中间的步骤省略了,直接帮我们在内部完成了new Object对象
* 举例:你想喝可乐,每天找我买,那么我就想我直接卖你可乐
*
* Class.newInstance()方法,它就是在找那个不带参数的构造方法。Instance-->实例、实体
* 然后用那个构造方法去创建实例对象(假如我们正好用那个不带参数的构造方法,
* 那么我就可以直接用class.newInstance()方法,这样可以省点事儿)
*
* 该方法内部的具体代码是怎样写的呢?
* 用到了缓存机制来保存默认构造方法的实例对象。
*/
public class _05_1Constructor构造方法 {
public static void main(String[]args)throws Exception{
//new String(new StringBuffer("abc"));
//调取String类的哪个构造方法(参数类型...)JDK1.5新特性,可接受可变参数类型
Constructor constructor = String.class.getConstructor(StringBuffer.class);
//Constructor constructor = String.class.newInstance("这里放无参数构造方法");
//传进去一个对象。
//(上面的StringBuffer是调用哪个构造方法,下面的是往调用的对象里面传入一个对象,上下必须保持一致)
//注意:需要对接收类型进行强转。因为newInstance的返回值类型是Object
String str = (String)constructor.newInstance(new StringBuffer("abc"));
//求String的第2个字符
System.out.println(str.charAt(2));
}
}
Field类(成员变量)
/*
* 反射:解析
* 例如一个对象中,有很多String类型的成员变量。我们想对String类型变量进行某个字符替换(如将所有String类型的'b'字母替换成'a'),
* 那么我们就用反射,获取这个对象中Field类中的String成员变量,通过数组接收,得到类的字节码
* 然后进行遍历,先判断,获取到的field数组是否为String.class类型的,
* 如果是,通过(String)Sfield.get(obj)方法获取字节码,
* 然后,进行替换,再将替换后的,通过field.set方法进行更新
*
*
* Field类代表某个类中的一个成员变量
* getClass();得到类的字节码
* getField();得到类中的某个成员字段
* getDeclaredField();对私有的x变量,进行获取
* setAccessible(true);强行设置访问(这就叫做“暴力反射”)
*/
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class _06_Field反射 {
private static Object str1;
public static void main(String[]args)throws Exception{
ReflectPoint p = new ReflectPoint(3,5);
//获取Person类中的某个成员变量的字段
//1.先得到类的字节码p.getClass()
//2.然后再得到类中的某个成员字段.getField("y");
Field fY = p.getClass().getField("y");
//fY的值是多少?是5,错!!
//fY获取的不是对象身上的变量,而是类上,要用它去取某个对象上对应的值
//fY不代表具体变量的值,它只是获取到对象的字段
//想要获取对象的具体值,
System.out.println(fY.get(p));//通过get获取具体对象身上的值
//Field fX = p.getClass().getField("x");
//通过getDeclaredField()方法,对私有的x变量,进行获取
Field fX = p.getClass().getDeclaredField("x");
fX.setAccessible(true);//强行设置访问(这就叫做“暴力反射”)
System.out.println(fX.get(p));
/* -------------------------------------
* 通过反射,将字符串中所有的b 替换成 a
* -------------------------------------
*/
changStringValue(p);//传进来一个对象
System.out.println(p);
}
private static void changStringValue(Object obj) throws Exception{
//通过成员变量数组,获取传入对象的变量
Field[] fields = obj.getClass().getFields();
//进行迭代
for(Field field : fields){
//使用equals与==的区别
//field.getType().equals(String.class)
//通过字段本身类型与String类型相比较,因为都是字节码,所以使用==
if(field.getType()==String.class)
{
String oldValue = (String)field.get(obj); //获取对象中的字节码
String newValue = oldValue.replace('b', 'a');//进行替换
field.set(obj, newValue);//通过field进行更新
}
}
}
}
Method类(方法)
public class _07_反射Method {
public static void main(String[]args) throws Exception{
/* -------------------------------------
* 通过反射,获取方法Method
* -------------------------------------
*/
String str = "abc";
Method methodCharAt = String.class.getMethod("CharAt",int.class);
System.out.println(methodCharAt.invoke(str, 1));
//如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?
// 说明该Method对象对应的是一个静态方法!
System.out.println(methodCharAt.invoke(null, 1));
//System.out.println(methodCharAt.invoke(str, new Object[](2)));
}
}
数组的反射
package cn.itcast.day1;
import java.lang.*;
import java.lang.reflect.Array;
import java.util.Arrays;
public class _09_Array数组 {
public static void main(String[] args) throws Exception
{
int[] a1 = new int[]{1,2,3};
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String []a4 = new String[]{"a","b","c"};
System.out.println(a1.getClass()==a2.getClass());
System.out.println(a1.getClass()==a2.getClass());
//System.out.println(a1.getClass()==a3.getClass());
System.out.println(a1.getClass().getName());//结果:[I [代表数组 I代表整数int
System.out.println(a1.getClass().getSuperclass().getName());//父类名
System.out.println(a4.getClass().getSuperclass().getName());
Object o1 = a1;
Object o2 = a4;
//Object[] o3 = a1;错误
Object[] o4 = a3;
Object[] o5 = a4;
System.out.println(a1);
System.out.println(a4);
//数组转成集合进行输出
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));
//数组的反射应用
printObject(a4);
printObject("ab");
}
private static void printObject(Object obj) {
Class clazz = obj.getClass();
if(clazz.isArray()){
int len = Array.getLength(obj);
for(int i=0; i<len; i++){
System.out.println(Array.get(obj, i));
}
}else{
System.out.println(obj);
}
}
}
内省
定义一个可以用JavaBean操作的类
public class ReflectPoint {
private int x;
public int y;
private Date birthday = new Date();
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String str1 = "basket";
public String str2 = "badseber";
public String str3 = "itcast";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
//覆盖toString方法
public String toString()
{
return str1+"::"+str2+"::"+str3;
}
}
JavaBean代码块
/*
* 内省:IntroSpector --> JavaBean --> 特殊的Java类
* JavaBean的属性是根据其中的setter和getter方法来确定的,
* 而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id
* 去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,
* 则把剩余部分的首字母改成小的。
*
* class Person
* {
* private int x;
* public int getAge(){return x;}
* public void setAge(int age){return this.x = age}
* }
* setId 属性名 Id
* setCPU 属性名 CPU
*
* PropertyDecriptor: 属性描述
*
* 小技巧:使用重构
*
*
*/
public class _12_内省IntroSpector {
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3,5);
String propertyName = "x";
//x-->X--getX--MethodGetX
//使用内省方式获取,接收的参数为:属性名,获取某个类的属性信息xxx.getClass()
PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());
//得到了JavaBeen属性信息,就可以得到getSet方法
Method methodGetX = pd.getReadMethod();//只读方法
//通过反射Method.invoke方法获取类型
Object retValue = methodGetX.invoke(pt1);
System.out.println(retValue);
//Set方法,为X重新赋值
Method methodSetX = pd.getWriteMethod();
methodSetX.invoke(pt1,7);
System.out.println(pt1.getX());
}
//内省复杂方法
public static void JavaBean() throws IntrospectionException
{
ReflectPoint pt1 = new ReflectPoint(3,5);
String str = "x";
//1.获取Bean内省的所有字段信息
BeanInfo info = Introspector.getBeanInfo(pt1.getClass());
//2.接收所有信息的属性
PropertyDescriptor[] pds = info.getPropertyDescriptors();
//3.进行遍历
for(PropertyDescriptor pd : pds){
if(pd.getClass().equals(str.getClass())){
Method m = pd.getReadMethod();
Object obj = m.invoke(pt1);
break;
}
}
}
使用BeanUtils包
* Jar包为我们提供了方便,可以直接调用里面的功能。
* 怎么找工具包?
* 找到里面最大的Jar包就是我们需要的工具包。
*
* 如何导入Jar包?
* 最好将Jar包放到工程内部,以免发给其它人导致缺包的现象。
* 1.在工程项目上点击右键,选择Folder-->命名lib
* 2.将选中的Jar包粘贴到lib文件夹中
* 3.选中工具包创建Build Path路径(Add to Build Path)
*
* 4.将工具包日志也粘贴到lib文件夹中
public class _13_使用BeanUtils工具包操作JavaBean {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3,5);
//参数解析(操作哪个对象,对象的某个属性,要替换的值)
//注意:要替换的类型为String类型"9"
//BeanUtils是将对象以字符串的形式操作的
BeanUtils.setProperty(pt1, "x","9");
/*
* java7的新特性 Map集合可以这样定义
* Map map = {name :"zxx",age:18};
*/
//将Map集合中的name属性,替换为lhm
//BeanUtils.setProperty(map,"name","lhm");
//将对象中的生日的时间,替换为111毫秒
//birthday.time;相当于人有脑袋,脑袋上有眼珠,眼珠的颜色是黄色
BeanUtils.setProperty(pt1, "birthday.time", "111");
//System.out.println(BeanUtils.getProperty(pt1,"birthday.time"));
BeanUtils.getProperty(pt1, "x").getClass();//获取对象属性类型
PropertyUtils.setProperty(pt1,"x",9);
System.out.println(PropertyUtils.getProperty(pt1,"x").getClass());
/*
* 总结:
* BeanUtils是将对象以字符串的形式操作的
* 而PropertyUtils是以对象本身属性形式操作
*/
}
}