------ ASP.Net+Android+IO开发.Net培训期待与您交流! ------
总结内容来源于张孝祥老师的Java高新技术
- eclipse的使用技巧
- 静态导入
- 可变参数与for循环增强
- 基本数据类型的自动拆箱装箱
- 枚举
- 反射
- javabean内省
- beanutils工具包
- 注解
- 泛型
- 类加载器
- 代理
- 线程并发库
eclipse 是一个开放源代码的、基于Java的可扩展开发平台.
myeclipse 是一个用于开发Java, J2EE的 Eclipse 插件集合.
eclipse的使用技巧
转换:File--->Switch WorkPlace--->要转换的工作间
新建:File--->Switch WorkPlace--->Other...
方法1:File---->new----> Java Project
方法2:左侧Package Explorer空白区右键--->new----> Java Project
方法1:选中Project或Project下的src文件夹右键--->new---->Packege
方法2:File---->new--->Package--Source Folder选择工程--->包命名
注意:给包命名时,一般选择公司的网址反转后+.具体有意义的名字,这样做的目的是为了尽量让包下新建的类,在整个Internet上的命名空间中唯一 .
路径:Window--->Preferences--->General--->Keys(Content Assist)
View:每个具体的小窗口(Eclipse中有2000多个)
Perspective:为完成某一功能而聚集在一起的多个View的集合
可在Window菜单下选择Open Perspective和Show View
设置整个工作间:Window--->Preferences--->Java--->Compiler(设置javac)和Installed JRE(设置java)
设置单个工程:选择Project名右键---->Properties--->Java Compiler 和Run/Debug Settings
注意:高版本的JDK可以运行低版本的JDK编译的程序,但低版本的JDK不能运行高版本的JDK编译的程序 , 就是说JDK是高版本向低版本兼容的 . 工作台的配置和单个项目的配置是继承的关系:单个项目如果没有配置会继承工作台的配置。单个项目如果配置了在会覆盖工作台的配置。
步骤:在要调试的代码行的最前边双击加断点,然后代码区右键--->debug as --->在调试透视图中,选中要查看的变量,右键选择watch . 调试完成后,通过右上角的按钮切换到所需的透视图.
设置路径:Window--->Preferences--->Java--->Editor----Templates
使用模板:选中要使用模板的代码行,右键选择Surround With——>选择要使用的模板
选中类名或代码区,右键后可选择Source和Refactor条目 . 可实现重命名、抽取方法、重写父类方法、产生构造函数等功能.
1 . 把该工程文件copy到工作台目录下.
2 . File-->Import--->Existing Projects into WorkSpace--->选择已经copy好的的工程
注意:如果该工程原来的库与现在的不同,则需要通过右键的Build Path条目,先删除导入时默认添加的库,然后选择自己的库.
其他小功能
alt+/ : 代码补全 , 相关代码联想.
ctrl+shift+/ : 把选中的代码区变成注释
ctrl+shift+\ : 把选中的注释变成正常代码
ctrl+单击类名或者方法 : 查看此类或者方法的源码
import语句:可以导入一个类或某个包中的所有类(不包括子包中的类)
import static 语句:导入一个类中的某个静态方法或所有静态方法。
- <pre name="code" class="java">import static java.lang.System.*;
- public class StaticImport
- {
- public static void main(String [] args)
- {
- //可以省略类名,直接调用方法
- out.println("-----staticImport----");
- long beginTime = currentTimeMillis();
- }
- }
- </pre><br>
- <pre></pre>
- <pre></pre>
如果类重名时,就指定具体的包名;如果方法重名时,就指定该方法所属的对象或类 , 来进一步确定这个类或者方法的所属 .
可变参数:Variable parameter
当一个方法中接受的参数个数不确定时 , 就用到了可变参数 .
写法 : 参数类型 ... 参数名
可变参数使用的注意事项:
1. 只能出现在参数列表的最后一位;
2. ...位于变量类型和变量之间,前后有无空格均可。
3. 调用参数方法时,编译器为该可变参数隐含创建一个数组(其实,可变参数就是一种数组的简写形式),在方法体中以数组形式访问可变参数。
- class VariableParameter
- {
- public static void main(String[] args)
- {
- getSum("可变参数1",20);
- getSum("可变参数2", 46, 8, 44);
- }
- public static void getSum(String s,int ...args)
- {
- System.out.print(s);
- System.out.print(",{");
- for(int i : args){
- if(args.length!=1)
- System.out.print(i+",");
- System.out.print(i);
- }
- System.out.print("}");
- }
- }
增强for循环 :
语法:for(参数类型 参数名:集合变量名){……}
注意事项:参数类型前可加修饰符,如加final,以方便内部类访问等;迭代变量必须在()中定义;集合变量名可以是数组或事项了Iterable接口的集合类.
- class VariableParameter
- {
- public static void main(String[] args)
- {
- getSum("可变参数1",20);
- getSum("可变参数2", 46, 8, 44);
- }
- public static void getSum(String s,int ...args)
- {
- System.out.print(s);
- System.out.print(",{");
- for(int i : args){
- if(args.length!=1)
- System.out.print(i+",");
- System.out.print(i);
- }
- System.out.print("}");
- }
- }
基本数据类型的装箱与拆箱:
基本数据类型:byte , short , int , long , char , float , double , boolean ;
对应的包装类:Byte,Short,Integer;Long;Character;Float;Double;Boolean;
装箱:把基本数据类型转换成对应的包装类。
拆箱:把包装类转成对应的基本数据类型。
在装箱和拆箱过程中有一个新特性--享元模式,如下边代码所示:
- class AutoBox
- {
- public static void main(String[] args)
- {
- Integer a = 13;//基本数据类型的装箱
- System.out.println(i+12);//基本数据类型的拆箱
- //基本数据类型装箱拆箱的一个特性------(享元模式)
- //当Integer封装的数据在一个字节之间(-128~127),则只建立一个对象,即享元
- Integer b = 127;
- Integer c =127;
- System.out.println(b == c);//结果为ture
- //当Integer封装的数据超出一个字节,则每个都新建一个对象。
- Integer d = 128;
- Integer e = 128;
- System.out.println(i3 == i4);//结果false
- Integer i5 =Integer.valueOf(3);
- Integer i6 =Integer.valueOf(3);
- System.out.println(i5 == i6);//true
- }
- }
枚举:Enum
什么是枚举?
就是要让某个类型变量的取值 , 只能为若干个固定值,否则,编译器报错 .
为什么要有枚举?
问题:要定义星期几或者性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday=0。
枚举就是要让某个类型的变量的值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制程序中填写的非法值,普通变量的方式无法在开发阶段实现这一目标。它跟泛型一样,都是把运行期的错误,提前到编译期来控制,提高了安全性。
注意:可以创建一个enum类,把它看做一个普通的类。除了它不能继承其他类了。(java是单继承,它已经继承了Enum).
- /*
- 用普通类如何实现枚举功能,定义一个WeekDay的类来模拟枚举功能。
- 思路:
- 1.私有构造方法。
- 2.每个元素分别用一个公有静态成员变量表示。
- 3.可以有若干公有方法或抽象方法,例如,要提供nextDay方法必须是抽象的。
- 总结:枚举是一种特殊的类,其中每个元素都是该类的一个实例对象。
- */
- public abstract class WeekDay1 {
- public final static WeekDay1 SUN = new WeekDay1(){
- public WeekDay1 nextDay() {
- return MON;
- }
- };
- public final static WeekDay1 MON = new WeekDay1(){
- public WeekDay1 nextDay() {
- return SUN;
- }
- };
- private WeekDay1(){}
- public abstract WeekDay1 nextDay();
- public String toString(){
- return this == SUN?"SUN":"MON";
- }
- }
枚举的基本应用
- public class EnumTest {
- /**
- * @param args
- */
- public static void main(String[] args) {
- //WeekDay1 weekDay = WeekDay1.MON;
- //System.out.print(weekDay.nextDay());
- WeekDay weekDay = WeekDay.FRI;
- //System.out.println(weekDay);
- System.out.println(weekDay.name());
- System.out.println(weekDay.ordinal());//获取FRI在枚举中的位置
- System.out.println(WeekDay.valueOf("SUN"));
- System.out.println(WeekDay.values().length);//获取枚举内的所有元素并返回数组
- }
- //带有构造方法的枚举
- public enum WeekDay{
- SUN(1),MON(),TUE,WED,THI,FRI,SAT;
- private WeekDay(){System.out.println("first");}
- private WeekDay(int i){ System.out.println("second");}
- }
- }
·枚举相当于一个类,其中可以定义构造方法、成员变量、普通方法和抽象方法.
·枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后面要有分号与其他成员分隔.
·把枚举中的成员方法或变量等放在枚举元素的前面,编译器会报告错误.
·枚举的元素是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义
*枚举只有一个成员时,就可以作为一种单例的实现方式.
·枚举的构造方法
1.必须定义成私有.
2.无参的元素默认调用无参的构造方法,有参则调用对应参数的构造方法.
3.枚举元素MON和MON()的效果是一样的,都是调用默认的构造方法.
- public class EnumTest2 {
- /**
- * @param args
- */
- public static void main(String[] args) {
- }
- /*
- 带方法的枚举
- 1.定义枚举Trafficlamp.
- 2.3个元素都需要传入int型的参数调用对应的构造函数.
- 3.3个元素都需要实现Trafficlamp的抽象方法.
- */
- public enum Trafficlamp{
- RED(30){
- public Trafficlamp nextTra() {
- return GREEN;
- }
- },
- GREEN(45){
- public Trafficlamp nextTra() {
- return YELLOW;
- }
- },
- YELLOW(5){
- public Trafficlamp nextTra() {
- return RED;
- }
- };
- public abstract Trafficlamp nextTra();
- private int time;
- private Trafficlamp(int time){this.time=time;}
- }
- }
当枚举只有一个成员时,就可以作为一个单例的实现方式。
反射
例如:变量类Field方法类Method构造方法类Contructor包类Package
- Java程序中的各个类也属于同一类事物,描述这类事物的Java类名就是Class
- 对比说明:众多的人用什么类来表示? 众多的类用什么来表示?
类→Class
- 对比说明:Person类代表人,它的实例对象就是张三、李四这样一个个具体的人,Class类代表Java类,它的实例对象又分别对应什么呢?
- 如何得到各个字节码对应的实例对象(Class类型)
- 九个预定义Class实例对象
boolean, byte, char, short, int, long, float,double, void通过 字节码.isPrimitive() 方法来判断是否是基本数据类型基本数据类型包装类的常量TYPE代表所包装的基本数据类型字节码例如:int.class==Integer.TYPE的结果为true.
- 数组类型的Class实例
总之:只要是在源程序中出现的类型,都有各自的Class实例.
- 得到某个类所有的构造方法:
- 得到某个类的某个构造方法 : getConstructor(Class<?>... );
- 利用获取的构造方法创建该类的实例 : newInstance(Object obj);
代码
- package com.itheima;
- import java.lang.reflect.Constructor;
- public class ConstructorDemo {
- public static void main(String[] args) throws Exception{
- Constructor<String> constructor = String.class.getConstructor(StringBuffer.class);
- String str = constructor.newInstance( new StringBuffer("abc"));
- System. out.print(str.charAt(2));
- }
- }
反射→Field类
- 获取某个对象的某个成员变量对象 :
- 那么如何获取这个变量在某个对象中的值呢?
- 获取某个对象的某个成员变量对象 :
- 取得某个变量在对象中的值
- package com.itheima;
- import java.lang.reflect.Field;
- class WhyNot{
- private int x;
- public int y;
- public WhyNot( int x, int y) {
- super();
- this. x = x;
- this. y = y;
- }
- }
- class FieldDemo{
- public static void main(String[] args) throws Exception{
- WhyNot wn = new WhyNot(3,5);
- Field fieldY = WhyNot. class.getField( "y");
- System. out.println(fieldY); //结果为y
- System. out.println(fieldY.get(wn)); //结果为5
- //取出私有的变量x
- Field fieldX = WhyNot. class.getDeclaredField( "x");
- System. out.println(fieldX); //结果为x
- fieldX.setAccessible( true); //设置变量x为可访问
- System. out.println(fieldX.get(wn)); //结果为3
- }
- }
Field练习→替换变量中的某个字符
- import java.lang.reflect.Field;
- /*
- 需求:扫描对象中所有变量,是否为String类型,是把字符串中的'b'换成'a'.
- */
- class TestString{
- public String str1 = "ball";
- public String str2 = "basketball";
- public String str3 = "itcast";
- }
- public class FIeldTest {
- public static void main(String[] args) throws Exception {
- TestString ts = new TestString();
- //获取所有变量,返回Field数组
- Field[] fields = ts.getClass().getFields();
- //高级for循环遍历
- for(Field field : fields){
- //判断变量类型是否为String
- if(field.getType() == String. class){
- //向下转型为String类型
- String oldValue = (String)field.get(ts);
- //调用String类中的replace方法
- String newValue = oldValue.replace( 'b', 'a');
- //把修改后的字符串重新赋值给 ts对象的变量
- field.set(ts, newValue);
- System. out.println(field.get(ts));
- }
- }
- }
- }
- 得到类中的某一个方法
- 调用方法
代码
- package com.itheima;
- import java.lang.reflect.Method;
- public class MethodDemo {
- public static void main(String[] args) throws Exception{
- String str = "abc";
- //获取String类的charAt方法
- Method md = String. class.getMethod( "charAt", int. class);
- //调用方法
- System. out.println(md.invoke(str, 1));
- //jdk1.4调用方法的参数是一个Object数组
- System. out.println(md.invoke(str, new Object[]{2}));
- }
- }
Method练习→执行类的main方法
- import java.lang.reflect.Method;
- /*
- 目标:写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法.
- */
- public class MethodTest {
- public static void main(String[] args) throws Exception{
- //假定main方法传进来的参数是一个完整的类名
- String startingClassName = args[0];
- //获取这个类的main方法
- Method mainMethod = Class.forName(startingClassName).getMethod( "main", String[]. class);
- //有下面两种方式来使用main方法
- mainMethod.invoke( null, new Object[]{ new String[]{"aa","bb" ,"cc" }});
- //mainMethod.invoke(null, (Object)new String[]{"aa","bb","cc"});
- }
- }
- class TestArguments{
- public static void main(String[] args){
- for(String arg : args){
- System. out.println(arg);
- }
- }
- }
数组与Object的关系及其反射类型
- 具有相同维数和元素类型的数组属于同一个Class类型 , 具有相同的Class实例对象.
- 所有数组的Class实例对象的getSuperclass()方法返回的父类都是Object类对应的Class实例对象 . 既所有数组都可以说成是Object类型的.
- 基本类型的一维数组可以被当成Object类型使用 , 不能当作Object[]类型使用 ; 例如 : int[]可以是Object , 但不能是Object[] ; 非基本类型的一维数组 , 既可以当作Object类型使用 , 又可以当作Object[]类型使用.
- Arrays.asList()方法处理int[]和String[]时的差异.
- int[]被当成一个Object元素存进集合 , String[]被当成一个Object[]数组 , 数组的元素被拆开后存进集合.
直接用代码来说明
- package com.itheima;
- import java.lang.reflect.Array;
- public class Test {
- public static void main(String[] args) {
- int[] a1 = new int[]{1,2,3};
- String[] strs = new String[]{ "a", "b"};
- String str = "xy";
- printObject(a1);
- printObject(strs);
- printObject(str);
- }
- public static void printObject(Object obj){
- Class c = obj.getClass();
- System. out.println(c.getName());
- //判断c的字节码是否为数组
- if(c.isArray()){
- //Array类中的方法全部都是静态,直接调用获取数组长度的方法
- int len = Array. getLength(obj);
- for( int x = 0; x < len; x++){
- //用Array类中的get()方法遍历出数组中的元素
- System. out.println(Array. get(obj, x));
- }
- }
- else
- System. out.println(obj);
- }
- }
hashCode的作用和产生内存泄漏的原因
反射的作用
- import java.io.*;
- import java.util.*;
- public class HashTest {
- public static void main(String[] args) throws Exception{
- //输入流读取配置文件
- InputStream is = new FileInputStream( "config.properties");
- Properties props = new Properties();
- //加载输入流
- props.load(is);
- //关闭流
- is.close();
- //根据key,取出vlaue(类名)
- String className = props.getProperty( "className");
- //创建该类的实例对象,并向下转型
- Collection collections = (Collection)Class.forName(className).newInstance();
- Hash h1 = new Hash(3,3);
- Hash h2 = new Hash(3,5);
- Hash h3 = new Hash(3,3);
- collections.add(h1);
- collections.add(h2);
- collections.add(h3);
- collections.add(h1);
- System. out.println(collections.size());
- }
- }
- class Hash{
- private int x;
- public int y;
- public Hash(int x, int y) {
- super();
- this. x = x;
- this. y = y;
- }
- }
注意:在实际开发中,配置文件获取不是用相对路径,而是绝对路径。
用ClassLoader管理资源和配置文件
- 我们把config.properties文件和TestReflect.java放在同一目录下时:
这种方式首先找到TestReflect这个类,然后拿到该类的加载器,再由类加载器去加载资源文件。
- config.properties文件和TestReflect.java依旧位于同一目录下:
这种方式是类加载器的简化形式,这时是用的相对路径的形式。
- config.properties位于com.itcast.resource包下时:
这种方式和方法二类似,也是用的对路径的形式
- config.properties位于com.itcast.resource包下时:
这种方式用的是绝对路径(简化的类加载器也可以使用绝对路径)