---------------------- android培训、java培训、期待与您交流! ----------------------
Java功力,由基础体现。
Eclipse的使用技巧
Workspace 与project 切换工作间与导入项目:一个工作间自带一套eclipse配置变量。常用快捷键:
1、显示系统提示:ALT+/(最常用:syso+alt+/ 补全代码) Ctrl+D:删除 2、程序代码自动排版:Ctrl+Shift+F(jsp文件是全部重排,java文件是可以对选定的代码重排) 3、自动汇入所需要的类别:Ctrl+Shift+O(注意和Ctrl+Shift+M区别) 4、查看使用类别的原始码:Ctrl+鼠标左键点击(链接进入) 5、将选取的文字批注起来:Ctrl+/(后期很少用) 6、将选取的文字取消注解:Ctrl+ \ 7、视景切换:Ctrl+F8 8、保存所有文件:Ctrl+Shift+S 9、关闭所有文件:Ctrl+Shift+F4 10、跳转到指定行:Ctrl+L(调试的时候很管用) 11、查找下一个:Ctrl+K 12、列出当前文件的结构:Ctrl+F3/Ctrl+O 13、列出类的继承结构:Ctrl+T(对于熟悉陌生的系统类很有用) 14、方法或类的原始码:F3 15、方法做在类的方法结构:F4 16、复制选定的代码:Ctrl+Alt+(箭头) 移动当前行:Alt+(箭头) 17、当前行插入一行:Ctrl+Shift+Enter 18、将选定字母全部转换成小写字母:Ctrl+Shift+Y 19、将选定字母全部转换成大写字母:Ctrl+Shift+X 20、将选定的换成连接:Ctrl 21、搜索所有文件中,包含的关键字:Ctrl+H(很管用) 22、系统辅助或者代码提示及补充:alt+/ 23、找另外一半括号:ctrl+shift+p 24、重新整理导入的包(只导入需要的包,不需要的会自动去掉):ctrl+shift+m(注意和Ctrl+Shift+O区分) 25、编辑框等窗口最大化:Ctrl + m 26、编辑器的回退,前进,切换:Alt + 左右箭头,Ctrl + F6 27. 重构:Ctrl+Shift+R |
Perspective与view:一个Perspective(透视图)代表了若干个view的集合,设置单个工程的javac和java,选择工程,右键->properties可以设置javac,右键->run as a open run dialog可以设置java运行参数.
静态导入
静态导入(static import)[08]
import语句可以导入一个类或某个包中的所有类。
importstatic语句导入一个类中的某个静态方法或所有静态方法。
语法举例:
import staticjava.lang.Math.sin;
import staticjava.lang.Math.*;
可变参数
问题:一个方法接受的参数个数不固定,例如:
System.out.println(add(2,3,5));
System.out.println(add(1,2,3,5));
可变参数的特点:
1、只能出现在参数列表的最后;这个要记住!!
2、“...”位于变量类型和变量名之间,前后有无空格都可以;
3、调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。以数组的形式来用。
package cn.itcast.day1; public class VarableParameter { public static void main(String[] args) { System.out.println(add(2,3)); System.out.println(add(1,2,3)); } public static int add(int x,int ... args){ int sum = x ; for (int i = 0; i < args.length; i++) { sum += args[i]; } return sum; } } |
for循环增强
语法:
for(type 变量名:集合变量名 )
{ … }
注意事项:
1、迭代变量必须在( )中定义!
2、集合变量可以是数组或实现了Iterable接口的集合类。
以上程序采用增强for 循环的示例:
public static int add(int x,int ... args){ int sum = x ; /*for (int i = 0; i < args.length; i++) { sum += args[i]; }*/ for(int arg : args){ sum += arg; } return sum; } |
基本数据类型的自动拆箱与装箱
自动装箱:Integer num1 = 12;
自动拆箱:System.out.println(num1 + 12);
基本数据类型的对象缓存:
Integer num1 = 12; Integer num2 = 12; System.out.println(num1 == num2);//true,这块相等,<=127都是真的。 Integer num3 = 129; Integer num4 = 129; System.out.println(num3 == num4);//false,这块不相等,因为是对象。
Integer num5 = Integer.valueOf(12); Integer num6 = Integer.valueOf(12); System.out.println(num5 == num6);//true,这块的道理同上。 Integer num7 = Integer.valueOf(128); Integer num8 = Integer.valueOf(128); System.out.println(num5 == num6);//false,这块的道理同上。
/*-128~127的数字(一个字节),一旦是Integer对象的话,缓存起来,再次使用时不新建。 * 享元模式:有很多小的对象,有很多相同的属性,变为一个对象,不同的属性作为方法的参数,作为外部状态,相同的属性称之为这个对象的内部状态,*/ |
享元设计模式(flyweight):当对象很小而又在很多地方都要用到时,就没有必要创建很多对象,而是使用固定的对象。
枚举
为什么要有枚举?
问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0;或即使使用常量方式也无法阻止意外。
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。
用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能
1、私有的构造方法。
2、每个元素分别用一个公有的静态成员变量表示
3、可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类。
总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象,例如可以调用WeekDay.SUN.getClass().getName和WeekDay.class.getName()。
枚举的高级应用
枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
枚举元素列表必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。
带构造方法的枚举
1、构造方法必须定义成私有的。
2、如果有多个构造方法,该如何选择哪个构造方法?
3、枚举元素MON和MON()的效果一样,都是调用默认的构造方法。传参数即可调用指定构造方法。
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");} } |
带方法的枚举
1、定义枚举TrafficLamp。
2、实现普通的next方法。
3、实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义。
4、增加上表示时间的构造方法。
public enum TrafficLamp{ RED(30){ public TrafficLamp nextLamp(){ return GREEN; } }, GREEN(60){ 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;} }
new Date(300){};//new 子类的实例对象,可以调用父类的有参的构造方法。
|
枚举只有一个成员时,就可以作为一种单例的实现方式。
反射
反射的基石àClass类 [17]
(Class也是一个类,代表的是一类事物?)
Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。
对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?
对比提问: Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。
人-->Person
Java类-->Class
Class类代表Java类,它的各个实例对象又分别对应什么呢?
①对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。
②一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?
如何得到各个字节码对应的实例对象(Class类型)
1、类名.class,例如,System.class;Person.class
2、对象.getClass(),例如,new Date().getClass()
3、Class.forName("类名"),例如,Class.forName("java.util.Date");
forName()的作用:返还字节码
1、虚拟机已经加载该字节码,直接放回。
2、JVM还没有这份字节码,用类加载器去加载,加载并返回。
9个预定义Class实例对象(8种基本数据类型和void都有对应的Class对象):
参看Class.isPrimitive方法的帮助
Int.class == Integer.TYPE
数组类型的Class实例对象:Class.isArray()
String str1 = "abc"; Class cls1 = str1.getClass(); Class cls2 = String.class; Class cls3 = Class.forName("java.lang.String");//必须是完整的类名。
System.out.println(cls1 == cls2);//true是一份字节码 System.out.println(cls1 == cls3);//true
System.out.println(cls1.isPrimitive());//false 不是基本类型字节码 System.out.println(int.class.isPrimitive());//true 是基本类型字节码 System.out.println(int.class == Integer.class);//false System.out.println(int.class == Integer.TYPE);//ture TYPE:代表是包装的基本类型的字节码。 System.out.println(int[].class.isPrimitive());//false 不是原始类型 System.out.println(int[].class.isArray());//true |
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…
反射
反射就是把Java类中的各种成分映射成相应的java类。
例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。
Constructor类
Constructor类代表某个类中的一个构造方法。
得到某个类所有的构造方法:
Constructor [] constructors=Class.forName("java.lang.String").getConstructors(); |
得到某一个构造方法:
Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class); |
//获得方法时要用到类型。
创建实例对象:[19]
通常方式:String str = new String(newStringBuffer("abc"));
反射方式:String str =(String)constructor.newInstance(new StringBuffer("abc"));
Constructor String str2 = (String)constructor1.newInstance(new StringBuffer("abc")); |
//调用获得的方法时要用到上面相同类型的实例对象。
Class.newInstance()方法:
例子:String obj =(String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。
---------------------------------------------------编译器只看变量的定义,不看代码的执行。
Field类
Field类代表某个类中的一个成员变量。(字段)
问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义,而不是具体的x变量。[20]
ReflectPoint pt1 = new ReflectPoint(3,5); Field fieldY = pt1.getClass().getField("y"); System.out.println("filedY=="+fieldY); //fieldY的值是多少?是5?错。 //fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值。 System.out.println(fieldY.get(pt1));
//获取私有(不可见)的变量,只要声明过的。------获取x的值 Field fieldX = pt1.getClass().getDeclaredField("x"); fieldX.setAccessible(true);//私有暴力获取。暴力反射。 System.out.println(fieldX.get(pt1)); |
private static void changeStringValue(Object obj) throws Exception { Field[] fields = obj.getClass().getFields();//扫描所有String类型的变量 //得到所有的字段,-->得到所属的字节码,-->getFields 得到所有的字段 for(Field field : fields){ //if(field.getType().equals(String.class)){ //字节码用 == 进行比较---->因为是同一份字节码。用==比较 if(field.getType() == String.class){ String oldValue = (String)field.get(obj);//取得字节码的值 String newValue = oldValue.replace('b', 'a'); field.set(obj, newValue);//需要set设置,field内容改变。(设置字节码的值) } } } |
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));
//str1.charAt(1) Method methodCharAt = String.class.getMethod("charAt", int.class); //用反射的方式,得到字节码的方法,在拿方法去作用于某个对象。(“方法名”,类型) System.out.println(methodCharAt.invoke(str1, 1)); |
如果传递给Method对象的invoke()方法的第一个参数为null,[ invoke(null,1) ]这有着什么样的意义呢?说明该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})形式。
用反射方式执行某个类中的main方法
目标:
写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。用普通方式调完后,大家要明白为什么要用反射方式去调啊?
问题:
启动Java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mainMethod.invoke(null,new String[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不把它当作jdk1.5的语法解释,因此会出现参数类型不对的问题。
解决办法:
mainMethod.invoke(null,newObject[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)newString[]{"xxx"}); 编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了。
为什么要用反射方式调用?因为不知道类名。
数组的反射
1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
2、代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
3、基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
4、Arrays.asList()方法处理int[]和String[]时的差异。接收的是Object[] obj数组 ------[24]
5、Array工具类用于完成对数组的反射操作。
private static void printObject(Object obj) { Class clazz = obj.getClass(); if(clazz.isArray()){ int len = Array.getLength(obj); for (int i=0;i System.out.println(Array.get(obj,i)); } }else{ System.out.println(obj); } } |
HashCode()方法的作用:
HashCode值:由此对象的内存地址换算而来。
哈希算法:将集合分为若干个储存区域,每个对象可以算出一个哈希码,将哈希码分组,每组分别对应某个储存区域,根据一个对象的哈希码就能确定该对象储存在哪个区域。
HashSet:采用哈希算法的集合。实现了Collection接口,只能存入不同HashCode对象,即只存入不同的对象,如果希望存入具有相同内容的两个对象,则需覆盖对象的HashCode和 equals方法。
ArrayList:实现了Collection接口,对象之间有指定顺序,允许重复元素——即使是同一对象,也会被顺序存入。
当一个对象被存入HasthSet中后,就不能再修改这个对象中那些参与计算哈希值的字段了,否则,修改后的哈希值与最初存入HashSet的就不相符了,此时HashSet将无法检索到此对象,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄漏。
反射的作用:实现框架功能
·框架与框架要解决的核心问题 [28]
我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
·框架要解决的核心问题
我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样能调用到你以后写的类(门窗)呢?
因为在写才程序时无法知道要被调用的类名,所以,在程序中无法直接new 某个类的实例对象了,而要用反射方式来做。
//注意一定要用完整的路径,但完整的路径不是硬编码。是运算出来的。 //InputStream ips = new FileInputStream("config.properties");
//类加载器 //先找到类,在用到类加载器方法。class的方法。 // InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties"); //指的从根目录下开始找。 //相对路径开始 InputStream ips = ReflectTest2.class.getResourceAsStream("config.properties");
Properties props = new Properties(); props.load(ips); ips.close();
String className = props.getProperty("className");//key Collection collections = (Collection)Class.forName(className).newInstance(); |
---------------------- android培训、java培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net/heima