黑马程序员_基础加强_2

来源:互联网 发布:js中= 和==和===的区别 编辑:程序博客网 时间:2024/06/05 15:17

 

----------- android培训java培训java学习型技术博客、期待与您交流! ------------ 

 

Method类

Method类代表某个类中的一个成员方法

得到类中的某一个方法:
Method CharAt = Class.forName("java.lang.String").getMethod("charAt",int.class);

调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str,1));

如果传递给Method对象的invoke()方法的一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!

jdk1.4 和jdk1.5的invoke方法的区别

 

 

 


用反射方式执行某个类中的main方法

目标:
写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法


如何为invoke方法传递参数?
mainMethod.invoke(null,new Object[]
{new String[]{"xxx"}});

 


class TestArguments
{
 public static void main(String args[])
 {
  for(String arg: args)
  System.out.println(arg);
 } 
}

 


为什么要用反射的方式调用其他类的main方法?
因为不知道类名  - -、

String startingClassName = args[0];

Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);

mainMethod.invoke(null,new Object[](new String[]("111","222","333")));
//JVM会自动拆包,所以我们传递时,主动打包一下。
mainMethod.invoke(null,(Object)new String[]{"111","222","333"});
//这种解决办法更方便

 

选中要执行的main,F2,出现完整名字,复制
反射函数中,右键,Run As 打开对话框
(open run dialog)
Arguments-粘贴

相当于在cmd中运行java ReflectTest cn.itcast.day1.TestArguments
执行反射所在的类,并传递要执行的main所在类的完整名

 

 

数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象

int[] a1=new int[3];
int[] a2=new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[4];

a1.getClass()==a2.getClass()?  true
a1.getClass()==a4.getClass()?  false
a1.getClass()==a3.getClass()?  false

 


代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class

基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用,非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。

Arrays.asList()方法处理int[]和String[]时的差异
Array工具类用于完成对数组的反射操作

 

思考题:怎么得到数组中的元素类型
a[0].getClass().getName();
可以得到数组中某个元素的类型,但不能得到整个数组的类型。
Object[] a = new Object[]{"a",1};
比如这样,会自动装箱

 

 

 


ArrayList_HashSet的比较及Hashcode分析


import java.util.*;
Collection collections = new ArrayList();
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(3,3);
ReflectPoint pt3 = new ReflectPoint(3,3);

collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);

System.out.println(collections.size());


右键-源代码(Source)-产生hashcode
(Generate hashCode())

 

为了提高查找的效率,有人发明了哈希值的方法


若两个对象equal值相等,则哈希值也应该相等
如果对象不打算存储在哈希集合,则没有必要弄hashcode


提示:
当一个对象被存储到HashSet集合之后,就不能修改这个对象中的那些参与计算哈希值的字段了;否则,对象修改后的哈希值与最初存储进HashSet集合中的哈希值就不同了。这种情况下,即使contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。


pt1.y=7;
collectons.remove(pt1);
System.out.println(collections.size());
//由于修改了参与计算哈希值的字段,导致找不到pt1元素,无法删除,collections的大小不变。长此以往,会导致内存可用容量变小。

 

 


反射的作用-实现框架功能

框架与框架要解决的核心问题
    比如我做房子卖给用户住,用户自己安装门窗和空调。我做的房子就是框架,用户需要使用我的框架,把门窗安装到提供的框架中。框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。


框架要解决的核心问题
    比如我在写框架(房子)时,用户可能还在上小学,不会写程序,如何调用到用户长大后写的类(门窗)呢?
    因为在写程序时,无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象,而要用反射方式来做。

综合案例
    先直接用new语句创建ArrayList和HashSet实例对象,演示用eclipse自动生成ReflectPoint类的equals和hashcode方法,比较两个集合的运行结果差异

    然后改为采用配置文件加反射的方式创建ArrayList和HashSet的实例对象,比较观察运行结果差异。

    引入了eclipse对资源文件的管理方式的讲解。

 

 

配置文件 config.properties
className=java.util.ArrayList

 

 

FileInputStream ips = new FileInputStream("config.properties");
//一定要记住,用运算出来的完整路径
Properties props = new Properties();
props.load(ips);
ips.close();
//良好的习惯,释放资源


String className=props.getProperty("className");
Collection collections =(Collection) Class.forName(className).newInstance();

 

配置文件放在哪儿?
让其配置文件,即得到路径
getRealPath();  //金山词霸/内部

.class

 

 

了解JavaBean
    javaBean是一种特殊的java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则

    如果要在两个模块之间传递多个信息,可以将这些信息封装到一个javaBean中  这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。    JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id。如果方法名为getId,中文意思即为获取id。 去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小写的。
    总之,一个类被当做JavaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。
    一个符合JavaBean特点的类可以当做普通类使用,但当做JavaBean用的好处如下:
    在JavaEE开发中,经常要使用到JavaBean。很多环境就要求按照JavaBean的方式进行操作,别人都这样用也这样要求,那么就没有什么挑选的余地。
    JDK中提供了对JavaBean进行操作的一些api,这套api就称为内省。用内省这套api操作JavaBean比用普通类的方式更方便。

 


如果一个类,符合JavaBean的特点,我们可以将其当做普通类,也可以当成JavaBean类来处理:
class Persson
{
 private int x;
 public int getAge()
 {return x;}
 public void setAge(int age)
 {this.x=age;}
}
若将这个Person类当成JavaBean类来看的话,里面有一个什么名称的属性?
答案:Age (因为JavaBean只根据方法判断属性)

 

gettime--time
getTime--time
getCPU--CPU
若去掉get和set后的第二个字母是小写,则获取JavaBean属性时,第一个字母也小写。

 

 


对JavaBean的简单内省操作
public static void main(String[] args) throws Exception
//为了代码紧凑抛出异常,否则应该try catch
{
 ReflectPoint pt1 = new ReflectPoint(3,5);
 String propertyName="x";
 //"x"->"X"-->"getX"-->MethodGetX-->
 PropertyDescriptor pd = new PropertyDescriptor(propertyName,pr1.getClass());

 /*
  若这个方法是只读,则只有get方法
  若只有可写,则只有set方法
  可读可写,才具备get和set方法
 */

 Method methodGetX = pd.getReadMethod();
 Object retVal = methodGexX.invoke(pt1);
 System.out.println(retVal);
 //选中 右键 抽取方法 - -  refactor--Extract Method
 //生成方法后,将接收类型改为Object

 

 Object value=7;
 //为了让其知道7也是个参数
 private static void setProperties(Object pt1,String propertyName,Object value) throws IntrospectionException,IllegalAccessException,InvocationTargetException
 {
 PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pr1.getClass());
 Method methodSetX = pd2.getReadMethod();
 methodSexX.invoke(pt1,value);
 //System.out.println(pt1.getX());
 }
}

 


对JavaBean的复杂内省操作

内省综合案例
    演示用eclipse自动生成ReflectPoint类的setter和getter方法。直接new一个PropertyDescriptor对象的方式来让大家了解JavaBean API的价值。先用一段代码读取JavaBean的属性,然后再用一段代码设置JavaBean的属性
    演示用eclipse将读取属性和设置属性的流水账代码分别抽取成方法:
        只要调用这个方法,并给这个方法传递了一个对象、属性名和设置值,他就能完成属性修改的功能
 得到BeanInfo最好采用“obj.getClass()”方式,而不要采用“类名.class”方式,这样程序更通用。

 

采用遍历BeanInfo的所有属性方式来查找和设置某个RefectPoint对象的x属性。在程序中把一个类当做JavaBean来看,就是调用IntroSprctor.getBeanInfo方法,得到的BeanInfo对象封装了把这个类当做JavaBean看的结果信息。

 

//以下为麻烦的方式,取某个属性的值
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor pd:pds)
{
 if(pd.getName().equals(propertyName))
 {
  Method methodGetX = pd.getReadMethod();
  retVal = methodGexX.invoke(pt1);
  break;
 }
}
return retVal;

 

 

使用BeanUtils工具包操作JavaBean

 

Beanutils 工具包
演示用eclipse如何加入jar包,先只是引入beanutils包,等程序运行出错后再引入logging包

在前面内省例子的基础上,用BeanUtils类先get原来设置好的属性,再将其set为一个新值
 get属性时返回的结果为字符串,set属性时可以接受任意类型的对象,通常使用字符串

用PropertyUtils类先get原来设置好的属性,再将其set为一个新值
 get属性时返回的结果为该属性本来的类型,set属性时只接受该属性本来的类型

 


下载人家的工具包
common-beanutils-current
解压后有使用规则

导入commons-beanutils (融合了另两个jar包)

//右键-Build Path-Configure Build Path-Add Internal JARs

让jar包跟着工程
右键-new-Folder-lib
选中jar包,右键-Bulid Path-Add to Build Path

需导入common-logging jar包

 

setProperties(pt1,propertyName,value);

System.out.println(BeanUtils.getProperty(pt1,"x").getClass().getName());
BeanUtils.getProperty(pt1,"x","9");
System.out.println(pt1.getX());

 


BeanUtils.setProperty(map,"name","1hm");?

 

 


了解和入门注解的应用

先通过@suppressWarnings的应用让大家直观地了解注解:
 通过System.runFinalizersOnExit(true);的编译警告引出@SuppressWarnings("deprecation")


@Deprecated
 直接在刚才的类中增加一个方法,并加上@Deprecated标注,在另外一个类中调用这个方法


@Override
 public boolean equals(Reflect other)方法与HashSet结合讲解


总结
 注解相当于一种标记,加了注解就等于为程序打上了某种标记。没加,则等于没有某种标记。以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包、类、字段、方法、方法的参数以及局部变量上。

看java.lang包,可以看到JDK中提供的最基本的annotation

 

 

起名字的小知识点
类名、属性名、变量名:
 名词、形容词+名词

方法:
 动词、动词+名词

 

 


明知过时的方法仍然要用 - -
加注释
@SuppressWarnings("deprecation")
则javac不会再提示过时  - -


@Deprecated
标志过时的方法,新用户没法用,老用户仍然可以用


@Override
查看是否覆盖了父类的方法
若没有覆盖,计算机会报错

 

 

 

 

 

 

----------- android培训java培训java学习型技术博客、期待与您交流! ------------ 

 

原创粉丝点击