---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
01、课程价值与目标介绍
1、课程大纲:
1.eclipse的使用技巧
2.静态导入
3.可变参数与for循环增强
4.基本数据类型的自动拆箱与装箱
5.枚举
6.反射
7.JavaBean内省
8.beanutils工具包
9.注解
10.泛型
11.类加载器
12.代理
13.线程并发库
02、Eclipse的使用技巧
1.IDE开发工具都支持使用工程化方式管理一个项目的程序开发过程,一般来说一个相对独立的项目就是一个工程,一个项目中涉及的多个java文件,资源文件等用一个工程进行管理。(在这里可以看看以前工作间中的某个工程的结构),在不使用工程管理的情况下,如果一个项目中包括多个Java源文件,编程人员需要精心维护这些源文件之间、以及源文件与其它文件的目录关系,需要逐一编译这些源文件,需要手工启动运行编译后的结果。如果将一个程序的所有源文件用一个工程来组织,开发工具能对所有源文件集中管理,记住每个源文件的位置和相互关系。工程中有哪几个源文件、启动类是哪个、启动参数设置等配置信息在工程中都记录。
一个workspace可以包含多个project,一个workspace保留了eclipse的一套环境选项的配置,例如,所使用的javac和java命令,等等,细节请查看window->preferences。如果要为eclispe再配置一套环境选项,可以再创建一个workspace。Package explorer视图窗口中的filters菜单项,可以显示空的父包(此功能默认是关闭的)。
2.一个Perspective代表了若干个view的集合,如何显示各种view。
3.设置单个工程的javac和java,选择工程,右键->properties可以设置javac,右键->run asopen run dialog可以设置java。
先用新的工作间,然后创建新工程,默认的语言即为5.0。先使用Integer x = 3;调整编译器的语法版本为1.4,看到eclipse窗口报错了。然后将这个工程的语言设置为6.0,马上又看到bad version .class运行错误了,这是因为myeclise自带的java为1.5 。然后再将整个工作间的javac设置为6.0(eclipse自带的是jdk1.5),然后看新建工程的javac,也随之改成了6.0,运行则又报bad version .class错误。将工程的编译语言再单独改为5.0,运行则没了问题。整个工作间的语言设置为6.0后,再将整个工作间的java也设置为自己安装的java6。
4.快捷键使用技巧:快捷键的位置:General->keys,设置alt+/键(丁:content a 就会搜索出)进行内容提示时,要注意解除alt+/键原来的绑定关系,直接输入alt+/就可以找到它的绑定关系,删除绑定关系时也可以使用removebinding这个按钮,课后必须教会大家在eclipse中。代码模板的设置位置:java->editor->Templates
03_Eclipse工程管理与快捷键配置
1、首选项:Window-->Preferences(首选项)-->Java-->Compiler(编译器) && Installed JREs(运行器)
2、新建工程Workspace:File-->Switch Workspace-->Other-->Workspace1
待Eclipse重新启动后,即可创建Java工程:File-->New-->Project-->JavaProject-->Project name:staticimport,其余默认,点击Finish即可
Perspective:透视图
3、新建Package:在staticimport工程的src目录下单击右键-->New-->Class->Packege:com.itheima.day1 Name:StaticImport
4、重构工程名称:在staticimport上单击鼠标右键-->Refactor-->Rename-->New Name:javaenhance
5、更改Eclipse中字体大小:Window-->Preferences-->General-->Appearance-->Colors andFonts
6、快速输出快捷键设置:Window-->Preferences-->General-->Keys-->在输入框中输入“content a”,选择Content Assist项目,然后解除绑定:Remove Command(Unbind Command)-->Binding:Alt+/-->Apply即可,如果还有其余快捷键与“Alt+/”有绑定的,则需要先将其解除绑定,确定即可,这是在Java项目的状态下输入syso即可弹出System.out.println();输出命令行。
04_Eclipse视图管理与程序调试、编译与运行环境
1、编译器和运行器必须保持一致,否则就会报错:Java.lang.UnsupportedClassVersionError:Badversion number in .class file
2、高版本的java可以运行低版本的javac编译的程序;而低版本的java则不能运行高版本的javac编译的程序
05_在Eclipse中配置java模板代码
1、新建java模板:Window-->Preferences-->Java-->Editor-->Templates(模板)-->New-->Name:tryf Pattern:try{
${line_selection}
}
finally{
${cursor}
}
-->Apply-->OK即可,运用的时候可以选中需要try的语句,单击鼠标右键:Surround With-->tryf()
06_在Eclipse中导入已有的工程
1、导入工程:首先将需要导入的工程拷贝到Workspace1的根目录下,然后在Eclipse中选择File-->Import-->General-->ExistingProjects into Workspace-->Next-->Select root directory:选择需要导入的文件根目录,Finish完成即可。
07_Java5的静态导入与编译器语法设置
1、import语句可以导入一个类或某个包中的所有类
2、import static语句导入一个类中的某个静态方法或所有静态方法
语法举例:
import static java.lang.Math.max;//静态导入java.lang.Math包中的某一个方法
import static java.lang.Math.*; //静态导入java.lang.Math包中的所有方法,一般建议使用导入相对应包中的方法,提高程序运行效率;
08_可变参数(VariableParameter)与OverLoad相关面试题分析
1、问题:一个方法接受的参数个数不固定,例如:
System.out.println(countScore(2,3,5));
System.out.println(countScore(1,2,3,5));
2、可变参数的特点:
1. 只能出现在参数列表的最后;
2. ...位于变量类型和变量名之间,前后有无空格都可以;
3. 调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
3、代码演示:
package com.itheima.day1;
public class VariableParameter {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated methodstub
System.out.println(add(2,3));
System.out.println(add(2,3,5));
}
public static int add(int x,int ...args){
int sum = x;
for(int i=0; i<args.length; i++){
sum = sum+args[i];
}
return sum;
}
}
09_Java5的增强for循环
注释快捷键:ctrl+Shift+/
1、语法:
for ( type 变量名:集合变量名 ) { … }
2、注意事项:
1.迭代变量必须在( )中定义!
2.集合变量可以是数组或实现了Iterable接口的集合类
3、举例:
public static int add(int x,int ...args){
intsum = x;
for(intarg:args) {
sum += arg;
}
returnsum;
}
10_基本数据的自动拆箱及享元设计模式(flyweight)
1、自动装箱:
Integer num1 = 12;
2、自动拆箱:
System.out.println(num1 + 12);
3、基本数据类型的对象缓存:
Integer num1 = 12;
Integer num2 = 12; 这块相等,<=127都是真的
System.out.println(num1 == num2);
Integer num3 = 129; 这块不相等,因为是对象,Integer取值范围为:-128-127
Integer num4 = 129;
System.out.println(num3 == num4);
Integer num5 = Integer.valueOf(12);
Integer num6 = Integer.valueOf(12) ; 这块的道理同上
System.out.println(num5 == num6);
11_枚举的作用介绍
1、为什么要有枚举
问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0;或即使使用常量方式也无法阻止意外。
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。
12_用普通类模拟枚举的实现原理
用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能。
1.私有的构造方法
2.每个元素分别用一个公有的静态成员变量表示
3.可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类。
EnumTest.java代码演示:
package com.itheima.day1;
public class EnumTest {
public static void main(String[] args) {
WeekDay weekDay = WeekDay.Mon;
System.out.println(weekDay.nextDay());
}
}
WeekDay.java代码演示:
package com.itheima.day1;
public abstract class WeekDay {
private WeekDay(){}
public final static WeekDay Sun =new WeekDay(){
@Override
public WeekDay nextDay() {
// TODO Auto-generated methodstub
return Mon;
}
};
public final static WeekDay Mon =new WeekDay(){
@Override
public WeekDay nextDay() {
// TODO Auto-generated methodstub
return Sun;
}
};
public abstract WeekDay nextDay();
/* public WeekDaynextDay(){
if(this==Sun){
return Mon;
}
else {
return Sun;
}
}*/
public String toString(){
return this==Sun?"Sun":"Mon";
}
}
13_Java5枚举的基本应用
枚举的基本应用
举例:定义一个Weekday的枚举。
扩展:枚举类的values,valueOf,name,toString,ordinal等方法(记住,讲课时要先于自定义方法前介绍,讲课更流畅)
总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象,例如可以调用WeekDay.SUN.getClass().getName和WeekDay.class.getName()。
代码演示:
package com.itheima.day1;
public class EnumTest {
public static void main(String[] args) {
WeekDay weekDay2 = WeekDay.FRI;
System.out.println(weekDay2);
System.out.println(weekDay2.name());
System.out.println(weekDay2.ordinal());//获取其索引位
System.out.println(WeekDay.valueOf("SUN").toString());
System.out.println(WeekDay.values().length);//获取其数组长度
}
public enum WeekDay{
SUN,MON,TUE,WED,THI,FRI,SAT;
}
}
14_实现带有构造方法的枚举
枚举的高级应用
1、枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
2、枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。
3、带构造方法的枚举
1.构造方法必须定义成私有的
2.如果有多个构造方法,该如何选择哪个构造方法?
3.枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
4、带抽象方法的枚举
1.定义枚举TrafficLamp
2.实现普通的next方法
3.实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义。
4.增加上表示时间的构造方法
5、枚举只有一个成员时,就可以作为一种单例的实现方式。
代码演示:
package com.itheima.day1;
public class EnumTest {
public static void main(String[] args) {
WeekDay weekDay2 = WeekDay.FRI;
System.out.println(weekDay2);
}
public enum WeekDay{
SUN(1),MON(),TUE,WED,THI,FRI,SAT;
private WeekDay(){System.out.println("first");}//空参数类型的构造函数
private WeekDay(int day){System.out.println("second");}//带有参数类型的构造函数
}
}
15_实现带有抽象方法的枚举
代码演示:
package com.itheima.day1;
import java.util.
public class EnumTest {
public static void main(String[]
new Date(300){};
}
//带有抽象方法的枚举——交通灯
public enum TrafficLamp{
RED(30){
public TrafficLamp nextLamp(){
return GREEN;
}
},
GREEN(45){
public TrafficLamp nextLamp(){
return YELLOW;
}
},
YELLOW(5){
public TrafficLamp nextLamp(){
return RED;
}
};
public abstract TrafficLamp nextLamp();
private int time;
private TrafficLamp(int time){
this.time = time;
}
}
}
16_透彻分析反射的基础_Class类
反射的基石-->Class类
1、 Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。
2、对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?
人Person
Java类Class
3、对比提问: Person类代表人,它的实例对象就是张三,李四这样一个个具体的人, Class类代表Java类,它的各个实例对象又分别对应什么呢?
1.对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。
2.一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?
4、如何得到各个字节码对应的实例对象( Class类型)
1.类名.class,例如,System.class
2.对象.getClass(),例如,new Date().getClass()
3.Class.forName("类名"),例如,Class.forName("java.util.Date");
5、九个预定义Class实例对象:
分别是boolean、byte、char、short、int、long、float、double和void
参看Class.isPrimitive(判定指定的 Class 对象是否表示一个基本类型)方法的帮助
int.class == Integer.TYPE
6、数组类型的Class实例对象
Class.isArray()
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…
常见Class方法:
Class<?>[] getInterfaces() 获取自己实现的多个接口
Method getMethods() 获取自己所有的方法列表
String getName() 获取类名
Package getPackege() 获取自己所属的包
17_理解反射的概念
1、反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
2、一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。
18_构造方法的反射应用
1、Constructor类代表某个类中的一个构造方法
2、得到某个类所有的构造方法:
例子:Constructor [] constructors=Class.forName("java.lang.String").getConstructors();
3、得到某一个构造方法:
例子:
Constructor constructor=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);//获得方法时要用到类型
4、创建实例对象:
1.通常方式:String str = new String(new StringBuffer("abc"));
2.反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));
//调用获得的方法时要用到上面相同类型的实例对象
Class.newInstance()方法:
例子:String obj =(String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。
代码演示:
package com.itheima.day1;
import java.lang.reflect.Constructor;
public class ReflectTest {
public static void main(String[] args)throws Exception {
// TODO Auto-generated methodstub
//new String(new StringBuffer("abc"));
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);//这里的StringBuffer是选择哪个构造方法
String str2 = (String)constructor1.newInstance(/*"abc"*/new StringBuffer("abc"));//这里的StringBuffer是指要用StringBuffer的时候必须传递一个StringBuffer进去
//这里编译器只知道constructor1是一个构造方法,但不知道是谁的构造方法,因此这里需要进行强制转换成String类型的即可。
System.out.println(str2.charAt(2));
//小结:程序编程分为编译和运行时期两个阶段,编译器只看代码的定义不看代码的运行
//1.得到方法的时候需要参数类型;2.用这个方法去调用这个函数的时候同样需要调用同样类型的对象
}
}
19_成员变量的反射
1、Field类代表某个类中的一个成员变量
2、演示用eclipse自动生成Java类的构造方法
3、问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义,而不是具体的x变量。
4、示例代码:
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY= pt1.getClass().getField("y");
//fieldY的值是多少?是5?错!fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值
System.out.println(fieldY.get(pt1));
//获取y的值
//Field fieldX =pt1.getClass().getField("x");//getField()只能获取可见参数,例如public可获取,而private则不能获取
Field fieldX = pt1.getClass().getDeclaredField("x");//获取可见所有参数(字段),权限足够大
fieldX.setAccessible(true);//将fieldX设置为可以访问,才能获取其值
System.out.println(fieldX.get(pt1));//暴力反射
快捷键:Alt + Shift + S -->产生想对应的构造方法Generate Constructor using Fields
20_成员变量反射的综合案例
需求:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
ReflectPoint.java 演示包:
package com.itheima.day1;
public class ReflectPoint {
private int x;
public int y;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "itcast";
public ReflectPoint(int x,int y) {
super();
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ",str3="
+ str3 + "]";
}
}
package com.itheima.day1;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectTest {
public static void main(String[] args)throws Exception {
// TODO Auto-generated methodstub
changeStringValue(pt1);
System.out.println(pt1);
}
//反射综合案例,重点掌握
public static void changeStringValue(Object obj)throws Exception{
Field[] fields = obj.getClass().getFields();
for(Field field : fields){
//if(field.getType().equals(String.class)){
if(field.getType()/*获取自己的类型*/ == String.class){
//由于比较的是同一份字节码,因此这里只能用"=="而不能用equals进行比较
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b','a');//将旧值替换成新值
field.set(obj,newValue);
}
}
}
}
21_成员方法的反射
1、Method类代表某个类中的一个成员方法
2、得到类中的某一个方法:
例子: Method charAt =Class.forName("java.lang.String").getMethod("charAt",int.class);
3、调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法!
4、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})形式。
面向对象:只要把对象变成私有private,如果谁要操作这个对象,那么这个方法就应该作用到谁的身上,专家模式。
代码演示:
package com.itheima.day1;
import java.lang.reflect.Method;
public class ReflectTest {
public static void main(String[] args)throws Exception {
// TODO Auto-generated methodstub
String str1 = "abc";
//str1.charAt(1);
Method methodCharAt = String.class.getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke(str1,1));//invoke表示调用某某的方法
System.out.println(methodCharAt.invoke(str1,newObject[]{2}));//按照JDK1.4的特点进行调用
}
}
22_对接收数组参数的成员方法进行反射
用反射方式执行某个类中的main方法
1、目标:
写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。用普通方式调完后,大家要明白为什么要用反射方式去调啊?
2、问题:
启动Java程序的main方法的参数是一个字符串数组,即public static voidmain(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mainMethod.invoke(null,newString[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不把它当作jdk1.5的语法解释,因此会出现参数类型不对的问题。
3、解决办法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了
代码演示:
package com.itheima.day1;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTest {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
// TODO Auto-generated methodstub
//TestArguments.main(newString[]{"111","222","333"});//使用静态方法调用main函数
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);
//mainMethod.invoke(null, new Object[]{newString[]{"111","222","333"}});
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
//每个数组的父类都是Object,这里可以利用new Object[]{}实例对象将new String[]{}进行封装,避免出错
//这里的第二种方法是直接在其前面加上(Object),首先是告诉编译器这里只是一个Object对象,其次就是强行将其转换成Object对象
}
}
/*选中TestArguments,按F2快捷键,弹出其所属对象,复制后,接着点击右键-->Run as-->Run Configurations-->Arguments-->Programarguments:com.itheima.day1.TestArguments-->Apply--Run即可*/
class TestArguments{
public static void main(String[] args){
for(String arg : args){
System.out.println(arg);
}
}
}
23_数组与Object的关系及其反射类型
数组的反射
1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。
2、代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
3、基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
4、Arrays.asList()方法处理int[]和String[]时的差异。
5、Array工具类用于完成对数组的反射操作。
代码演示:
package com.itheima.day1;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ReflectTest {
public static void main(String[] args)throws Exception {
// TODO Auto-generated methodstub
int[] a1 = newint[]{1};
int[] a2 = newint[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() ==a3.getClass());
//System.out.println(a1.getClass() ==a4.getClass());
System.out.println(a1.getClass().getName());
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(a1);
System.out.println(a2);
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));
}
}
小结:[I:正中括号表示数组,而I则表示是整数
24_数组的反射应用
Array工具类用于完成对数组的反射操作。
代码演示:
package com.itheima.day1;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ReflectTest {
public static void main(String[] args)throws Exception {
// TODO Auto-generated methodstub
printObject(a4);
printObject("xyz");
//获取数组中的元素类型
Object[] aa = new Object[]{"a",1};
System.out.println(aa[1].getClass().getName());
}
private static void printObject(Object obj) {
// TODO Auto-generated methodstub
Class clazz = obj.getClass();
if(clazz.isArray()){
for(int x=0; x<Array.getLength(obj); x++){
System.out.println(Array.get(obj, x));
}
}
else{
System.out.println(obj);
}
}
}
小结:从Object[] a = new Object[](“a”,1);中分析得知,我们无法直接获取a这个元素的类型,但是我们可以通过获取其其中某一个元素的字节码名称而得知,即:a[0].getClass().getName()
25_ArrayList、HashSet的比较以及Hashcode分析
代码演示:
package com.itheima.day1;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class ReflectTest2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated methodstub
//Collection collections = new ArrayList();
Collection collections = newHashSet();
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(5,5);
ReflectPoint pt3 = new ReflectPoint(3,3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);
pt1.y = 7;
collections.remove(pt1);//内存泄露,这里的pt1是移除不掉的,因为其Hashcode地址值已变
System.out.println(collections.size());
}
}
package com.itheima.day1;
public class ReflectPoint {
private int x;
public int y;
public ReflectPoint(int x,int y) {
super();
this.x = x;
this.y = y;
}
@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;
}
}
26_框架的概念以及用反射技术开发框架的原理
反射的作用-->实现框架功能
1、框架与框架要解决的核心问题
我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
2、框架要解决的核心问题
我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样能调用到你以后写的类(门窗)呢?
因为在写才程序时无法知道要被调用的类名,所以,在程序中无法直接new 某个类的实例对象了,而要用反射方式来做。
3、综合案例
1.先直接用new 语句创建ArrayList和HashSet的实例对象,演示用eclipse自动生成 ReflectPoint类的equals和hashcode方法,比较两个集合的运行结果差异。
2.然后改为采用配置文件加反射的方式创建ArrayList和HashSet的实例对象,比较观察运行结果差异。
3.引入了elipse对资源文件的管理方式的讲解。
代码演示:
package com.itheima.day1;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;
public class ReflectTest3 {
public static void main(String[] args)throws Exception{
// TODO Auto-generated methodstub
InputStream 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();
//Collection collections = new ArrayList();
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(5,5);
ReflectPoint pt3 = new ReflectPoint(3,3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);
System.out.println(collections.size());
}
}
config.properties文件:
className=java.util.HashSet
注意:这里在建立config.properties文件的时候,需要在javaenhance工程上单击右键,新建File文件,而其自动生成的文件则在JRE文件目录下,因此可以避免其余错误
27_用类加载器的方法管理资源和配置文件
1.getRealPath();//金山词霸//内部
一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的。
2.类加载器可以将.class文件加载到内存当中去
3.配置文件一定要放在classpath执行路径下
注意:配置文件一定要区分相对路径和绝对路径,否则很容易出错
28_由内省引出JavaBean的讲解
1、JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
2、如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,至于你把它存到哪个变量上,用管吗?如果方法名为getId,中文意思即为获取id,至于你从哪个变量上取,用管吗?去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。
setId()的属性名id
isLast()的属性名last
setCPU的属性名是什么?CPU
getUPS的属性名是什么?UPS
总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。
一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当JavaBean用肯定需要带来一些额外的好处,我们才会去
3、了解和应用JavaBean!好处如下:
1.在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作,别人都这么用和要求这么做,那你就没什么挑选的余地!
2.JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来访问私有的x,怎么做,有一定难度吧?用内省这套api操作JavaBean比用普通类的方式更方便。
InstroSpector:内省,检查视察的意思,主要对JavaBean进行操作,其中JavaBean是一个特殊的Java类
4、JavaBean的常规代码演示:
class Person {
private int x;
public int getAge() {
return x;
}
public void setAge() {
this.x = age;
}
}
5、Age --> 如果第二个字母是小的,则把第一个字母变成小的-->age
例如:
gettime-->time setTime-->time getCPU-->CPU
29_对JavaBean的简单内省操作
代码演示:
package com.itheima.day1;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpectorTest {
public static void main(String[] args)throws Exception {
// TODO Auto-generated methodstub
ReflectPoint pt1 = new ReflectPoint(3,5);
String propertyName = "x";
//原始处理方法就是:"x"-->"X"-->"getX"-->MethodGetX-->
//Object retVal =getProperty(pt1,propertyName);
//PropertyDescriptor:属性描述符
ObjectretVal = getProperty(pt1,propertyName);
System.out.println(retVal);
Objectvalue = 7;
setProperties(pt1,propertyName, value);
System.out.println(pt1.getX());//setProperty设置某个对象的哪个属性,并将其设置成某个值
}
//设置value的值
private static void setProperties(Objectpt1, String propertyName,
Object value) throws IntrospectionException,
IllegalAccessException,InvocationTargetException {
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt1, value);
}
//获取methodGetX的值
private static Object getProperty(Object pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException{
PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodGetX = pd.getReadMethod();
ObjectretVal = methodGetX.invoke(pt1);
return retVal;
}
}
小结:
1.通过PropertyDescriptor这个对属性描述的方法可以获取其对应元素的相关方法,然后通过getProperty()方法获取需要的值
2.这里想获取某个对象的方法时可以利用重构:Extract Method-->Alt+Shift+M;
3.如果想提升其重构后代码的复用性,这里可以将重构后的ReflectPoint换成Object对象
30_对JavaBean的复杂内省操作
采用遍历BeanInfo的所有属性方式来查找和设置某个RefectPoint对象的x属性。在程序中把一个类当作JavaBean来看,就是调用IntroSpector.getBeanInfo方法,得到的BeanInfo对象封装了把这个类当作JavaBean看的结果信息
部分代码演示:
private static Object getProperty(Objectpt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException{
/*PropertyDescriptor pd = newPropertyDescriptor(propertyName,pt1.getClass());
Method methodGetX = pd.getReadMethod();
Object retVal = methodGetX.invoke(pt1);*/
//对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 = methodGetX.invoke(pt1);
break;
}
}
return retVal;
}
31_使用BeanUtils工具包操作JavaBean
Bean工具包
1、演示用eclipse如何加入jar包,先只是引入beanutils包,等程序运行出错后再引入logging包。
2、在前面内省例子的基础上,用BeanUtils类先get原来设置好的属性,再将其set为一个新值。
get属性时返回的结果为字符串,set属性时可以接受任意类型的对象,通常使用字符串。
3、用PropertyUtils类先get原来设置好的属性,再将其set为一个新值。
get属性时返回的结果为该属性本来的类型,set属性时只接受该属性本来的类型。
4、演示去掉JavaBean(ReflectPoint)的public修饰符时,BeanUtils工具包访问javabean属性时出现的问题。
导入需要的jar包操作步骤:在javaenhance工程上单击鼠标右键-->New-->SourceFolder-->Floder Name:lib--.复制需要使用的jar包,直接粘贴到新建的lib目录下,然后将其增加到build path环境中:单击导入的jar包右键-->Build Path-->Add toBuild Path即可
在使用IntroSpectorTest.java的时候运用到了JavaUtils时,只导入commons-beanutils.jar包是不够的,而且会报错:org/apache/commons/logging/LogFactory,因此这里还需要按照导入beanutils jar包的方法导入logging包,并且添加到Build Path环境变量中
部分代码演示如下:
Map map = {name:"zxx",age:16};
BeanUtils.setProperty(map, "name", "lhm");*/
PropertyUtils.setProperty(pt1,"x", 9);
System.out.println(PropertyUtils.getProperty(pt1,"x").getClass().getName());
小结:BeanUtils是以字符串的形式对JavaBean进行操作,而PropertyUtils则是对属性本身类型对JavaBean进行操作;如果需要类型转换,则使用BeanUtils,否则使用PropertyUtils
---------------------- ASP.Net+Android+IOS开发、 .Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net