JAVA_java基础加强小结




JDK1.5新特性
1.静态导入 import static
一般导入和静态导入的区别:
import语句可以导入一个类或某个包中的的所有类
import static语句可以导入一个类中的某个静态方法或所有的静态方法

2.可变参数
特点:
1.只能出现在参数列表的最后
2.  ... 位于变量类型和变量名之间,前后有无空格都可以
3.调用可变参数的方法是,编译器为该可变参数隐式创建一个数组,在方法体中义数组的形式访问可变参数

3.增强for循环
语法:
for(变量类型 变量名:集合(数组)名){}
注意:
迭代变量必须定义在()中定义
集合变量可以是数组或实现了Iterator接口的集合类

4.自动装箱与拆箱
自动装箱:基本数据类型自动提升为基本数据类型对象的过程
自动拆箱:基本数据类型对象自动转换为基本数据类型的过程

注意:Integer对象的值在-128~127之间时,两个相等的对象比较结果是true,如果超过了这个范围,结果就是false
享元模式(flyWeight),在一定的数据范围内共享一个的对象(频繁使用的,并且数值较小的)。

5.枚举
为什么要有枚举?
枚举就是要让某个类型的变量的取值只能为若干个固定值的一个,否则,编译报错。
枚举可以让编译器在编译时,就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现。
用普通类如何实现枚举功能,定义一个weekday的类来模拟枚举功能
私有构造函数
每个元素分别用一个公有的静态成员变量表示
可以有若干个功能公有方法或抽象方法。
采用抽象方法定义,将大量的判断性代码转移成了一个个独立的类(内部类)。
构造方法
位于元素列表之后,最后一个元素要加 ;
构造方法要用private修饰
调用枚举成员时,会调用默认无参构造,即默认格式是SUN()。
要想调用带参构造的时候,元素后加(1),例如 SUN(1)
带抽象方法
枚举的每个元素分别由枚举类的子类来生成的实例对象,实现抽象方法。这些子类采用类似用内部类的形式进行定义。
枚举只有一个成员时,就可以作为一种单例的实现方式

6.注解
基本注解:
@SuppressWarnings
通过System.runFinalizersOnExit(true);的编译警告可以引出
@SuppressWarnings("deprecation")//编译时不报过时
@Deprecated //过时了
直接在类中增加一个方法,并加上@Deprecated,在另一个类中调用这个方法。
可以直观的看出方法被划线了,提示过时。
@Override
public boolean equals(Reflect other)方法。
如果类型不统一的话,那么equals()就不能成为重写,而是重载。
总结:
1.注解相当一种标记,在程序上加了注解就等于打上了某种标记,没加,就等于没有某种标记。
以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。
标记可以加载包,类,字段,方法,方法的参数以及局部变量上。
2.看java.lang包,可看到JDK中提供的最基本的annotation type。
元注解:
例子:
@Retention(RetentionPolicy.RUNTIME)
//Retention元注解,取值:RetentionPolicy.RUNTIME,RetentionPolicy.SOURCE,RetentionPolicy.CLASS
@Target({ElementType.TYPE,ElementType.METHOD})
//Target元注解,作用范围:类型,方法,字段,变量,参数。。
//如果,想要作用的范围是多个,可以采用{}形式设置。
public @interface ItheimaAnnotation
{
}

@ItheimaAnnotation
public class AnnotationTest
{
@SuppressWarnings("deprecation")//编译时不报过时
public static void main(String[] args)
{
System.runFinalizersOnExit(true);

//通过反射调用,判断类中是否含有指定的注解
if(AnnotationTest.class.isAnnotationPresent(ItheimaAnnotation.class))
{
//获取指定的注解
ItheimaAnnotation annotation=(ItheimaAnnotation) AnnotationTest.class.getAnnotation(ItheimaAnnotation.class);
System.out.println(annotation);
}
}
}
注意:元注解以及其枚举属性值不用记,只要会看jdk提供那几个基注解的API帮助文档的定义或其源代码,按图索骥即可查到。
或者直接查看java.lang.annotation包下面的类即可。
属性:
例子:
@ItheimaAnnotation(color="red",value="abc",array={1,2,3,4},annotationArr=@MetaAnnotation("fly")) //设置属性的值
public class AnnotationTest
{
@SuppressWarnings("deprecation")//编译时不报过时
@ItheimaAnnotation("xyz") //设置属性的值
public static void main(String[] args)
{
System.runFinalizersOnExit(true);

if(AnnotationTest.class.isAnnotationPresent(ItheimaAnnotation.class))
{
ItheimaAnnotation annotation=(ItheimaAnnotation) AnnotationTest.class.getAnnotation(ItheimaAnnotation.class);
System.out.println(annotation.color());
//调用属性的时候,以调用方法的形式
//获取属性的值的时候,当方法和类上都有注解,并且都设置了值,那么以类的值为准。
//没有设置值的情况下,以默认值为准。
System.out.println(annotation.value());

System.out.println(annotation.array().length);
//如果数组属性中只有一个元素,这时候属性值部分可以省略大括号

System.out.println(annotation.lamp().nextLamp().name());

System.out.println(annotation.annotationArr().value());
}
}
}


@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface ItheimaAnnotation
{
//属性的声明
String color() default "blue";
String value();
//数组类型的属性
int[] array() default {3,4,5};
//枚举类型的属性
EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;
//注解类型的属性
MetaAnnotation annotationArr() default @MetaAnnotation("scy");
}

7.泛型
泛型是给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会除掉“类型”信息,是程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型不一样。
由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往泛型集合中计入其他类型的数据。
例如:用反射得到集合,在调用其add方法即可。
//通过反射给泛型添加元素
//泛型是给编译器使用的。
ArrayList<Integer> al2=new ArrayList<Integer>();
al2.getClass().getMethod("add", Object.class).invoke(al2, "abc");
System.out.println(al2.get(0));
术语:
整个称为ArrayList<E>泛型类型
ArrayList<E>中的E称为类型变量或类型参数
整个ArrayList<Integer>称为参数化的类型
ArrayList<Integer>中的Integer称为参数类型的实例或实际类型参数
ArrayList<Integer>中的<>念为typeof
ArrayList称为原始类型
参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象, 编译报告警告,例如:
Collection<String> c=new Vector();
原始类型可以引用一个参数化类型交给你的对象,编译报告警告,例如:
Collection c=new Vector<String>();
参数化类型不考虑类型参数的继承关系:
Vector<String> v=new Vector<Object>();//错误
Vector<Object> v=new Vector<String>();//错误
在创建数组实例时,数组的元素不能使用参数化类型的类型,例如
Vector<Integer> vectorList[]=new Vector<Integer>[10];//错误
?通配符:
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以提哦啊用与参数化无关的方法,不能调用与参数化有关的方法
例子:
private static void printCollection(Collection<?> collection)
{
System.out.println(collection.size());
for (Object object : collection)
{
System.out.println(object);
}
}
扩展:
限定上边界:
正确:Vector<? extends Number> x=new Vector<Integer>();
错误:Vector<? extends Number> x=new Vector<String>();
限定下边界:
正确:Vector<? super Integer> x=new Vector<Number>();
错误:Vector<? super Integer> x=new Vector<Byte>();
提示:
限定通配符总是包括自己。
类型参数的类型判断:
根据调用泛型方法是实际传递的参数类型或返回值的类型来推断,规则如下:
1.当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,那么根据调用方法是该处的实际应用类型来确定。
即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型。
swap(new String[3],3,4) --> static <T> void swap(T[]a ,int i,int j);
2.当某个类型变量在整个参数列表中的所有参数和返回值的多处被应用了,如果调用方法时着多处的实际应用类型都对应同一种类型来确定。
add(3,5) --> static <T> T add(T a,T b)
3.当某个类型变量在整个参数列表中的所有参数和返回值的多处被应用了,如果调用方法时这多处的实际应用对应了不同的类型,且没有使用返回值,这时候取多个参数中的最大交集类型。
例如:下面语句实际对应的类型就是Number,编译没问题,只是运行时出问题。
fill(new Integer[3],3.5f) --> static <T> void fill(T[] a,T v)
4.当某个类型变量在整个参数列表中的所有参数和返回值的多处被应用了,如果调用方法时这多处的实际应用对应了不同的类型,并且使用返回值,这时候优先考虑返回值的类型。
例如:下面语句实际对应的类型就是Integer了,编译将报告错误,将变量x的类型改为float,对比eclipse报告的错误提示,接着在将变量x的类型改为Number就可以了
int x=(3,3.5f) --> static <T> T add(T a,T b);
5.参数类型的类型推断具有传递性,下面第一种情况推断实际参数类型为Object,编译没有问题,而第二种情况则根据参数化的Vector类实例将类型变量直接确定为String类型,编译将出现问题。
copy(new Integer[5],new String[5]) --> static <T> void copy(T[] a,T[] b);
copy(new Vector<String>(),new Integer[5]) --> static <T> void copy(Collection<T> a,T[] b);
定义泛型类型:
如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,这时候要采用泛型类型的方式进行定义,也就是类级别的泛型。
格式:
public class GenericDao<T>{
private T file1;
public void save(T t){}
public T getById(int id){}
}
类级别的泛型时根据引用该类名时指定的类型信息李艾参数化类型变量的。
例如:
GenericDao<String> dao=null;
new GenericDao<String>();
注意:
在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。
当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不是被静态变量和静态方法调用。因为静态成员是被所有参数实例化的类所共享的,所以静态成员不应该有类级别的类型参数。



MyEclipse
调试
想要查看某个遍历的值?
选中变量,右键watch,在debug下就可以查看变量的值

透视图
透视图perspective包含视图view

编译
高版本的java能运行低版本的javac编译的程序
低版本的java不能运行高版本的javac编译的程序

导入外部程序
把外部的工程拷贝到指定目录下。java页面下Import导入File System

overload与override的区别
Overload是重载的意思,Override是覆盖的意思,也就是重写。
重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。
overload对我们来说可能比较熟悉,可以翻译为重载,它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。
在使用重载要注意以下的几点:
1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int);
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响;
4、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。


重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。
子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。
子类方法的访问权限只能比父类的更大,不能更小。如果父类的方法是private类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。


override可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。
对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。
除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。
在覆盖要注意以下的几点:
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。


反射
概述:把java类中的各种成分映射成相应的java类


反射的基础:Class类
Class类:在java中表示众多的java类。
描述了,类的名字,类的访问属性,类所属的包名,字段名称的列表,方法名称的列表等。
如何得到各个字节码对应的实例对象(Class类型)
类名.class,例如:System.class;
对象.getClass(),例如,new Date().getClass();
Class.forName("类名"),例如,Class.forName("java.util.Date");
九个预定义的Class实例对象
表示八个基本类型和 void。
这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即 boolean、byte、char、short、int、long、float 和 double。 
基本类型对象.TYPE
基本类型对象.TYPE:获取基本类型对象的类型。
Class.isPrimitive()
判断是否是基本数据类型
Class.isArray()
数组类型的Class实例对象
例子:
String str1="abc"; 
Class cls1=str1.getClass();
Class cls2=String.class;
Class cls3=Class.forName("java.lang.String"); 
System.out.println(cls1==cls2);
System.out.println(cls2==cls3);
System.out.println(cls1.isPrimitive()); //验证是否是基本类型
System.out.println(int.class);
System.out.println("int.class==Integer.class"+(int.class==Integer.class));
System.out.println("int.class==Integer.TYPE:"+(int.class==Integer.TYPE));
System.out.println("判断数组是否是基本类型"+int[].class.isPrimitive());
System.out.println("判断是否是数组类型:"+int[].class.isArray());
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如:int[],void

反射-Constructor类
代表某个类中的一个构造方法
得到某个类中的所有的构造方法
Constructor[] constructor=Class.forName("java.lang.String").getConstructors();
得到某一个构造方法
Constructor constructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class);
创建实例方法
通常方式:
String str=new String(new StringBuffer("abc"));
反射方式:
String str=(String)constructor.newInstance(new StringBuffer("abc"));
Class.newInstance()方法
例子:String obj=(String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后该构造方法创建实例对象。
该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。
例子:
//new String(new StringBuffer("abc")); 
Constructor constructor=String.class.getConstructor(StringBuffer.class);//传递数据类型
String str=(String) constructor.newInstance(new StringBuffer("abc"));
//传递相同类型的对象 System.out.println(str);
总结,Constructor大量的消耗资源


反射-Field类
代表某个类中的成员变量
获取Field类变量的值例子:
public class ReflectPoint {
private int x;
public int y;

public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}

ReflectPoint rp=new ReflectPoint(3, 5);
try {
Field field=rp.getClass().getField("y");
//field不是对象的变量,而是类上,要用它去取某个对象上对应的值
System.out.println(field.get(rp));

Field fieldx=rp.getClass().getDeclaredField("x");
//暴力反射
fieldx.setAccessible(true);
System.out.println(fieldx.get(rp));

} catch (Exception e) {
e.printStackTrace();
}

利用Field类进行反射修改变量的值例子:
public String str1="ball";
public String str2="basketball";
public String str3="itcast";

public String toString(){
return str1+":"+str2+":"+str3;
}

private static void changeStringValue(Object obj) throws Exception {
Field[] fields = obj.getClass().getFields();


for (Field field : fields) {


// field.getType().equals(String.class);


// 同一个字节码,使用双等号进行判断
if (field.getType() == String.class) {
String strValue = (String) field.get(obj);
String newValue = strValue.replace('b', 'a');
// 设置对象的新值
field.set(obj, newValue);
}
}
}

反射-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方法的区别:
JDK1.5:public Object invoke(Object obj,Object...args)
JDK1.4: public Object invoke(Object obj,Object[] args)
即按JDK1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数。
所以,调用charAt方法的代码也可以用JDK1.4改写为charAt.invoke("str",new Object[]{1})形式。
例子:
String str1="abc"; 
Method methodCharAt=String.class.getMethod("charAt", int.class);
System.out.println(methodCharAt.invoke(str1, 1)); //JDK1.5
System.out.println(methodCharAt.invoke(str1, new Object[]{1})); //JDK1.4

main方法的反射例子:
class TestArguments{
public static void main(String[] args) {
for (String string : args) {
System.out.println(string);
}
}
}

String startingClassName=args[0];
Method main=Class.forName(startingClassName).getMethod("main", String[].class);
main.invoke(null, new Object[]{new String[]{"111","222","333"}}); //把传入的数组看成一个整体
main.invoke(null, (Object)new String[]{"111","222","333"});//把传入的数组看成一个整体

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

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

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

Arrays.asList()方法处理int[]和String[]时的差异:
处理int[]时,把他当做一个Object类型看待,打印结果是带有hashCode的值。
处理String[]时,当做Object[]类型看待,打印结果是具体的数组元素值。
例子:
int[] a1=new int[]{1,2,3};
int[] a2=new int[4];
int[][] a3=new int[2][3];
String[] a4=new String[]{"aa","bb","cc"};
System.out.println(a1.getClass()==a2.getClass());
// System.out.println(a1.getClass()==a3.getClass());
// System.out.println(a1.getClass()==a4.getClass());
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(a4.getClass().getSuperclass().getName());

Object aObj1=a1;
Object aObj2=a4;
// Object[] aObj3=a1;
Object[] aObj4=a3;
Object[] aObj5=a4;

System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));

Array工具类完成对数组的反射例子:
private static void printObject(Object obj) {
Class arr=obj.getClass();
if(arr.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);
}
}

ArrayList和HashSet的比较和hashCode的分析
例子:
Collection collections=new HashSet();

ReflectPoint rp1=new ReflectPoint(3,3);
ReflectPoint rp2=new ReflectPoint(5,5);
ReflectPoint rp3=new ReflectPoint(3,3);

collections.add(rp1);
collections.add(rp2);
collections.add(rp3);
collections.add(rp1);

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

@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}

@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ReflectPoint other = (ReflectPoint) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
hashCode方法的作用:
总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。 
你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。 
那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢? 
这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。 
也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。    
于是,Java采用了哈希表的原理。哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。 
哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。 
初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。   
这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。 
如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了, 
就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。 
所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。   
所以,Java对于eqauls方法和hashCode方法是这样规定的: 
1、如果两个对象相同,那么它们的hashCode值一定要相同;2、如果两个对象的hashCode相同,它们并不一定相同     上面说的对象相同指的是用eqauls方法比较。   
你当然可以不按要求去做了,但你会发现,相同的对象可以出现在Set集合中。同时,增加新元素的效率会大大下降。
内存泄露:
指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。 

反射的作用
实现框架功能
因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类的对象,而要用反射的方法来做。
例子:
//一定要用完整的路径,但完整的路径不是硬编码,而是运算出来的
InputStream is=new FileInputStream("config.properties");
//调用配置文件的方法。
InputStream is=ReflectTest2.class.getClassLoader().getResourceAsStream("com\\itheima\\day01\\config.properties");
InputStream is=ReflectTest2.class.getResourceAsStream("config.properties");
InputStream is=ReflectTest2.class.getResourceAsStream("/com/itheima/day01/resource/config.properties");

InputStream is=new FileInputStream("config.properties");
Properties prop=new Properties();
prop.load(is);
is.close();
String className=prop.getProperty("className");
Collection collections=(Collection) Class.forName(className).newInstance();

内省
为什么要学内省?
开发框架时,经常使用java对象的属性来封装程序的数据,每次都使用反射技术来完成此类操作过于麻烦。
什么是java对象的属性和属性的读写方法?
内省访问JavaBean属性的两种方式:
通过PropertyDescriptor类操作Bean的属性。
通过Introspector类获得Bean对象的BeanInfo,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个描述器就可以获取某个属性对应的getter/setter方法。然后通过反射机制来调用这些方法。
例子:
private static Object getProperties(Object rp1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException
{

//简单的方法
/*PropertyDescriptor pd=new PropertyDescriptor(propertyName,rp1.getClass());
Method methodGetX= pd.getReadMethod();
Object retVal=methodGetX.invoke(rp1);*/


//复杂的方法
BeanInfo beanInfo=Introspector.getBeanInfo(rp1.getClass());
PropertyDescriptor[] pds=beanInfo.getPropertyDescriptors();
Object retVal=null;
for (PropertyDescriptor pd : pds)
{
if(pd.getName().equals(propertyName))
{
Method methodGetX=pd.getReadMethod();
retVal=methodGetX.invoke(rp1);
break;
}
}
return retVal;
}
Beanutils工具包:
特点:
方便快捷。
可以以属性链的形式存在。
例子:
/*
//JDK1.7的新特性
Map map={name:"zxx",age:18};
BeanUtils.setProperty(map,"name","lhm");
*/
System.out.println(BeanUtils.getProperty(rp1,"x"));
System.out.println(BeanUtils.getProperty(rp1,"x").getClass().getName());
Beanutils.setProperty(rp1,"x","9");
System.out.println(rp1.getX());

BeanUtils.setProperty(rp1,"birthday.time","111");
System.out.println(BeanUtils.getProperty(rp1,"birthday.time"));
//BeanUtils对对象的属性进行操作使用字符串的形式。

PropertyUtils.setProperty(rp1,"x",9);
System.out.println(PropertyUtils.getProperty(rp1,"x"));
//PropertyUtils对对象的属性进行操作是以属性本身的类型进行操作。

类加载器
概述和作用:
加载类的工具
java虚拟机可以安装多个类加载器,系统默认三个主要类加载器,每个类加载器负责加载特定位置的类
BootStrap,ExtClassLoader,AppClassLoader
类加载器也是java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,正是BootStrap。
java虚拟机中的所有类装载器采用父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其制定一个父级类装载器对象或默认使用采用系统类装载器为其父类加载。

委托机制:
当java虚拟机要加载一个类,到底要派出那个类加载器去加载呢?
首先当前线程的类加载器去加载线程中的第一个类。
如果类A中引用了类B,java虚拟机将使用加载类A的类加载器来加载类B
还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类
每个类加载器加载类时,先委托给其上级类加载器
当所有父类的加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的子类,因为没有getChild()方法,即使有,不知道找哪一个。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值