黑马程序员-Java高新技术笔记1
来源:互联网 发布:mac无法打开文件夹 编辑:程序博客网 时间:2024/06/05 18:42
---------------------- 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
- 黑马程序员 + Java高新技术笔记1
- 黑马程序员-Java高新技术笔记1
- 黑马程序员---Java高新技术学习笔记-1
- 黑马程序员--Java高新技术笔记
- 黑马程序员 - Java 高新技术1
- 黑马程序员---Java高新技术1
- 黑马程序员 Java高新技术1
- 黑马程序员——java高新技术1学习笔记整理
- 黑马程序员—JAVA高新技术视频笔记
- 黑马程序员------java学习笔记之高新技术
- 黑马程序员 java高新技术笔记之反射
- 黑马程序员-Java高新技术笔记2
- 黑马程序员-Java高新技术笔记3
- 黑马程序员---Java高新技术学习笔记(中篇)
- 黑马程序员-java学习笔记-高新技术_2
- 黑马程序员-java学习笔记-高新技术
- 黑马程序员---Java高新技术学习笔记-2
- 黑马程序员---Java高新技术学习笔记-3
- grub stage 1.5
- SQL SERVER FLOOR(),CEILING()函数
- 体验学生信息管理系统
- 用数组模拟双向链表
- iOS图形处理和性能
- 黑马程序员-Java高新技术笔记1
- 非对称加密算法
- t谈函数原型设计
- hdu 4699 Editor 多校第十场 (模拟)
- 黑马程序员-Java高新技术笔记2
- 黑马程序员-Java高新技术笔记3
- uva270 Lining Up 搜索?
- 查询语句的解释
- 黑马程序员之交通灯管理系统