Eclipse快捷键
1、显示系统提示:ALT+/
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+(箭头)
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、文件重命名:F2
28、刷新:F5
29. 重构:Ctrl+Shift+R
静态导入
使用静态导入的好处:提高编写代码的效率。
静态成员的使用:使用import static 引入静态成员。
很简单的东西,看一个例子:
没有静态导入
Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
有了静态导入
import static java.lang.Math.*;
sqrt(pow(x, 2) + pow(y, 2));
其中import static java.lang.Math.*;就是静态导入的语法,它的意思是导入Math类中的所有static方法和属性。
这样我们在使用这些方法和属性时就不必写类名。
需要注意的是默认包无法用静态导入,另外如果导入的类中有重复的方法和属性则需要写出类名,否则编译时无法通过。
可变参数:(底层是通过数组来实现的)
减少代码量,方便输入
如果有多个参数,可变参数要定义在最后边..
位于变量类型和变量名之间,前后有无空格都可以;
在调用可变参数的方法时,编译器会为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
public static void m(String... s)
{
System.out.println("m(String)" +s);
}
调用m(String… s)
for(String s2:s)
{
System.out.println(s2);
}
基本数据类型的自动装箱与拆箱
自动封箱解箱只在必要的时候才进行。还有其它选择就用其它的
自动装箱:Integer num = 12;
自动拆箱:Int num = new Integer(12);
基本Boolean/Byte/Integer(数值范围:-128至127)数据类型的对象缓存:
Integer num1 = 12;
Integer num2 = 12;
System.out.println(num1 == num2);结果为true
Integer num3 = 129;
Integer num4 = 129;
System.out.println(num3 == num4);结果为false
因为数值范围在:(-128至127)数据类型的对象缓存。
简单类型和封装类型之间的差别
封装类可以等于null ,避免数字得0时的二义性。
Integer i=null;
int ii=i;会抛出NullException 异常。
相当于 int ii=i.intValue();
枚举
枚举(Enum)可以使用构造方法,构造方法必须是私有的(private)。
枚举(Enum)可以使用成员变量和成员方法
例1.这是在5.0之前使用模式做出枚举
final class Season
{public static final Season SPRING=new Season();
public static final Season WINTER=new Season();
public static final Season SUMMER=new Season();
public static final Season AUTUMN=new Season();
private Season(){...}
}
例2.使用5.0的新特性枚举类
import java.lang.Enum.*;
enum Season2
{ SPRING,
SUMMER,
AUTUMN,
WINTER
}
经过编译运行,例1和例2完全是等价的。
反射(class类)
在java中就是反射就是把Java类中的各种成分映射成相应的java类。
反射的作用:
用于工具,架构,动态开发等开发工程
三种得到类对象的途径:
1.Class.forName(“name”) //输入全类名
2.object.getClass() //得到该对象的类对象
3.object.class
Constructor的反射
String str1 = new String(new StringBuffer("abc")); //用Constructor构造此String对象
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String)constructor1.newInstance(new StringBuffer("abc"));
Class.newInstance的作用:调用用默认的构造方法,省去中间Constructor的步骤
Class.forName("java.lang.String").newInstance();
成员变量的反射
Field FLY = rp1.getClass().getField("y"); //FLY不是对象上的变量,代表类身上字节码的变量,要用它去取某个
对象上对应的值。
FLY.get(rp1); //用get取得y的值
暴力反射:取私有变量
Field FLX = rp1.getClass().getDeclaredField("x");//x为私有变量,所以用此方法
FLX.setAccessible(true);//设置可用
System.out.println(FLX.get(rp1));
数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperclass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用,非基本数据类型的一维数组,既可以当
作Object使用,也可以当作Object[]使用。
Arrays.asList()方法:将数组转换为List。处理int[]和String[]时的差异。
Array工具类用于完成数组反射的操作
怎样得到整个数组的元素类型:无法得到,只能得到具体元素的类型—— a[i].getClass().getName();
ArrayList与HashSet比较
HashCode:由此对象的内存地址换算而来。
哈希算法:将集合分为若干个储存区域,每个对象可以算出一个哈希码,将哈希码分组,每组分别对应某个储存区域,
根据一个对象的哈希码就能确定该对象储存在哪个区域。
HashSet:采用哈希算法的集合。实现了Collection接口,只能存入不同HashCode对象,即只存入不同的对象,如果希望
存入具有相同内容的两个对象,则需覆盖对象的HashCode和 equals方法。
ArrayList:实现了Collection接口,对象之间有指定顺序,允许重复元素——即使是同一对象,也会被顺序存入。
提示:当一个对象被存入HasthSet中后,就不能再修改这个对象中那些参与计算哈希值的字段了,否则,修改后的哈希
值与最初存入HashSet的就不相符了,此时HashSet将无法检索到此对象,这也会导致无法从HashSet集合中单独删除当
前对象,从而造成内存泄漏(..无用后仍在内存中占用空间,从而造成内存的浪费)。
反射的作用—实现框架的功能
在写程序的时候无法知道要调用的类名,所以在程序中无法直接new某个类的实例对象,而要用反射的方式来做。
InputStream ips = new FileInputStream("config.properties");
Properties pr = new Properties();
pr.load(ips);
ips.close();
String className = pr.getProperty("className");
Collection collections = (Collection)Class.forName(className).newInstance();
采用类加载器管理资源和配制文件
用完整路径:安装目录+内部目录——getRealPath(); +内部目录
类加载器:当文件或资源放入源文件目录时,Ecplice会自动将其复制到.class目录中。类加载器从ClassPath指定的根
目录开始查找(需写从根目录开始的完整路径名)。
格式:类名.class.getClassLoader().
getResourceAsStream(“xxx”); 获取资源目录。
getClassLoader()也可省略。此时只需写上资源的名称即可。
缺点:无OutputStream,无法写入文件,只能读取。
内省——用来操作JavaBean
JavaBean:特殊的Java类,主要用于传递数据信息,这种Java类的方法用于访问私有的字段,方法名称具有特定规则。
Person类具有getAge()和setAge()方法,那么Person类的JavaBean名称为age--如果age的第二个字母为小写,那么第一
个字母也变为小写。
内省的简单操作
PropertyDescriptor属性描述符:获取属性名称及对象,再调用getReadMethod或getWriteMethod方法返回一个
Method对象,再调用invoke()即可。
ecplice方法的抽取:选中代码——右键——Refactor—ExtraceMethod,即可生成代码对应的方法
用复杂的方式操作内省
采用遍历BeanInfo的所有方式来查找和设置某个ReflectPoint的x属性。在程序中把一个类当作JavaBean来看,就是调
用IntroSpector.getBeanInfo,得到的BeanInfo对象封装了这个类当作JavaBean看的结果信息。
Object retVal = null;
BeanInfo beaninfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beaninfo.getPropertyDescriptors();
for(PropertyDescriptor pd : pds){
if(pd.getName().equals(propertyName)){
Method methodGetX = pd.getReadMethod();
retVal = methodGetX.invoke(pt1);
}
}
return retVal;
Beanutils工具包
用ecplice加入jar包,分别导入BeanUtils和loading包,并设置BuildPath。
用BeanUtils代替上面的内省操作。
get属性返回的结果为字符串,set可设置任意类型的的对象,通常使用字符串。
PropertyUtils:get属性返回的结果为该属性本来的类型,set属性只接受该属性本来的类型。
Java的三个基本注解
注解:等于为程序打上了某种标记,可以加在类,包,字段,方法,方法的参数及局部变量上。
@Deprecated :标记此程序元素已过时,通常是因为它很危险或存在更好的选择。
@SuppressWarnings :取消显示指定的编译器警告。
@Override :表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类
方法,则编译器会生成一条错误消息。
注解的应用
元注解@Retention--定义注解类的存在区域,有三种取值:RetentionPolicy.SOURCE、 RetentionPolicy.CLASS、
RetentionPolicy.RUNTIME,分别对应java源文件、class文件、内存中的字节码。
元注解@Target:确定注解类可用范围,取值ElementType.METHOD···
为注解增加基本属性
定义基本类型的属性
在注解类中增加String color();
引用:@MyAnnotation(color=“red”)
用反射获得注解对应的实例对象后,再通过对象调用属性对应的方法。
MyAnnotation a=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation)
System.out.println(a.color);
为属性定义缺省值String color() default “red”;
Value属性 String value();
如果一个注解只有一个名称为value的属性,且你只想设置value的属性,可以省略,@MyAnnotation(“red”);
为注解增加高级属性
数组类型的属性
int[] arrayAttr () default {1,2,4,5};
@MyAnnotation(arrayAttr={2,3,4});如果数组中只有一个元素,则可以省略大括号。
枚举类型的属性
EnumTest.TracfficLamp lamp() default
EnumTest.TracfficLamp.RED;
@MyAnnotation(lamp = EnumTest.TracfficLamp.YELLOW);
注解类型的属性
MetaAnnotationannotationAttr()default @MetaAnnotation(“lhm”);
@MyAnnotation(annotationAttr = @MetaAnnotation(“flx”));MetaAnnotation为注解类
Class类型的属性
Class annotationClass() default String.class;
@MyAnnotation(annotationClass=String.class);
泛型
Jdk1.5的集合类在希望你在定义集合时,明确表示你要向集合中装哪种类型的数据,无法加入指定类型以外的数据。
ArrayList<Integer> c=new ArrayList<<Integer>();
c.add(“abc”);//编译报错
泛型是提供给java编译器使用的,让编译器挡住程序的非法输入,对于参数化的泛型,getClass返回值和原始类型完全
一样。由于编译生成的字节码会去掉泛型的信息,只要跳过编译器,就可以往泛型集合中加入其它类型的数据,如:用反射得到集合,再调用其add方法即可。
了解泛型
ArrayList<E>类定义和ArrayList<Integer>类引用中涉及的术语:
1、整个ArrayList<E>称为泛型类型
2、ArrayList<E>中E称为类型变量或类型参数
3、整个ArrayList<Integer>称为参数化的类型
4、ArrayList<Integer>中的Integer叫类型参数的实例或实际类型参数
5、ArrayList<Integer>中的<>念typeof
6、ArrayList称为原始类型
参数化类型与原始类型的兼容性-编译警告
Collection<String> = new Vector();
Collection = new Vector<String >();
参数化类型不考虑类型参数的继承关系
Vector<String> v = new Vector<Object>(); //错!
Vector<Object> v = new Vector<String>();//错!
在创建数组实例时,数组的元素不能使用参数化的类型
Vector<Integer> v[] = new Vector<Integer>[10];
Vector v1 = new Vector<Integer>();
Vector<Object> v = v1; //编译可以通过!编译器只会按行解释
泛型的?通配符及扩展
<?>可以引用各种参数化的类型,可以调用与参数无关的方法,不能调用与参数有关的方法
限定通配符的上边界
正确:Vector<? extends Number> v=new Vector<Integer>();
错误:Vector<? extends Number> v=new Vector<String>();
限定通配符的下边界
正确:Vector<? Super Integer> v=new Vector<Number>();
错误:Vector<? extends Integer > v=new Vector<Byte>();
通配符包括自己
定义泛型的方法
交换数组中两个元素的位置的泛型方法定义如下:
private static<T> void swap(T[] a,int i,int j){
T temp = a[i];
a[i] = a[j];
a[j] = temp; }
用于放置泛型的类型参数的尖括号应出现在方法的所有修饰符之后和返回类型之前。
只有引用类型才能作为泛型方法的实际参数,基本类型则不可以如:swap(new int[]{1,3},1,2);
定义泛型时也可以使用extends修饰符,如<V extends Serializable&cloneable> void method();
也可以用类型变量表示异常,可以用于方法的throws列表中,但不能用于catch中。
泛型中可以有多个类型参数,在定义它们的尖括号中用逗号分开。
Public static <K,V> V getValue(K key) {return
map.get(key);}
定义泛型类
类中的多个方法要使用同一个泛型参数,此时要定义类级别的泛型。
public class GenericDao<T>{
private T field1;
public void save<T obj>{}
public T getById(int ID){}
}
类级别的泛型是根据引用类名指定的泛型信息来参数化变量的.
GenericDao<String> dao=null;
new GenericDao<String>();
注意
1、在对泛型参数化时,必须是引用类型,不能是基本类型。
2、当一个类被声明为泛型时,只能被实例变量和方法调用(还有内嵌类),而不能被静态变量和静态方法调用。因为
类静态成员是被所有参数化的类所共享的,所以静态成员不应该拥有类级别的类型参数。
*通过反射获得泛型的参数化类型
Vector<Date> v = new Vector<Date>();
通过v.getClass()是无法获得泛型的参数化类型的。
将其传递给一个方法,可实现此功能。
public static void applyVector(Vector<Date> v){}
Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class);
Type[] types = applyMethod.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType)types[0];
System.out.println(pType.getRawType());//Vector
System.out.println(pType.getActualTypeArguments
类加载器之间的父子关系和管辖范围图
类加载器的委托机制
当java虚拟机加载类时,到底用哪个类加载器?
◇首先当前线程的类加载器去加载线程中的第一个类
◇如果类A引用了类B,那么java虚拟机将使用加载类A的类加载器去加载类B
◇还可以直接调用ClassLoader.loaderClass()方法来指定某个类加载器去加载
每个类加载器加载时,又委托给其上级的类加载器。
当所有祖宗类加载器没有加载到该类,则回到发起者类加载器,还加载不到,则抛出ClassNoFoundException,不是再
找发起者类加载器和儿子,因为没有getChild方法。——从上到下的加载。
自定义类加载器
工作机制
父类——>loadClass/findClass()/得到class文件的内容转换成字节码—>difineClass()/将一个 byte 数组转换为
Class 类的实例
实现步骤
◇自定义的类加载器必须继承ClassLoader
◇覆盖findClass方法
◇覆盖difineClass()方法
用自定义加载类实现加密及解密-难!
查看视频及源文件 MyClassLoader.class