普通的包导入可以导入一个包中的类或者方法。着是为了方便书写而出现的。
当我们在使用静态方法的时候,要使用类名导入。现在为了省掉类名的书写,就出现了静态导入。
可变参数:在我们使用的一个方法中,有时可能要使用的参数是不一定的。在一起的话,我们就要写好几个有同样功能但是参数列表不一致的重载方法。在1.5
之后jdk出现新特性:可变参数(可变参数只能放在参数列表的最后).其实编译器为可变参数创建了一个数组在方法中以数组的形式来使用。
例如:想有一个实现求几个传入参数的和的方法。这样就可以使用可变参数了
public static int add(int x,int…args){
int sum=0;
for(int i=0;i<args.lengtn;i++)
sum+=Iarg[i];
return sum;
}
增强for循环
for(type 变量名:集合变量名){}
集合变量可以是数组,也可以是实现了iterable接口的集合类
将上面的循环改成加强for循环。
定义变量名的小技巧。比如下面这个,将变量命名为arg,将数组集合定义为args。
for(int arg:args){sum+=arg;}
基本数据类型的字段装箱与拆箱
装箱Integer iObj=3; 将int型直接装箱成对象。
拆箱System.out.println(iObj+12);对象是不能直接进行加法运算的,所以此时要进行字自动拆箱的动作,以便于参与运算
小知识:Integer s1=13; Integer s2=13;
Integer s3=128; Integer s4=128; s3 s4不是同一个对象。他们分别创建了新的对象。
s1 s2 是同一个对象。因为对于这些比较小的数即小于127的情况下,为节省内存,就不会从新创建对象,这就是一种设计模式:享元模式(flyweight)(一个方法中有很多小的内部对象重复出现的几率很大,而且内部有很多的相同属性,所以就将这些小元素变成一个对象,那些有不同属性的对象就作为外部参数传入,而那些有相同属性的对象就称为内部状态)
枚举:
问题引入:要定义星期几或者行吧的变量,该怎么定义比呢?会想到假设用1-7表示的话,可能有些人就会写成int Weekday=0z这个时候该则么班呢,每个人都有自己的不同定义方法。因此,为了规范。就应用枚举。首先定义一个枚举,将所对应的的值规定好,以后别人使用的时候,如果不符合这个规定,编译器就会报错。
用普通的java类实现枚举:创建一个WeekDay的类。将构造方法私有,在类内部创建7个静态常量。
public static final WeekDay SUN=new WeekDay();
所以在外面只能使用着几个已经定义好的对象
WeekDay weekday=WeekDay.SUN;
更近一步的方法,将类中的方法抽象,那么类也会变成抽象。那么,在该类中只能通过子类来创建父类的对象。使用匿名内部类,在内部类覆写父类的方法
public enum WeekDay
{
SUN,MON,TUE,WED,THI,FRI,SAT ;//元素列表必须在第一行
//SUN(),意思是在创建对象的时候使用指定的参数对象的构造方法
private WeekDay(){}//构造函数必须私有
}
在枚举中为我们定义好了许多方法。name()得到名字 ordinal()得到顺序
比如静态方法valueOf(“”)有字符串返回对象
values()返回对象的数组
如果枚举只有一个成员的时候,就可以最为一个单例的实现。
反射:把java类中的各种成分映射成相应的java类
反射的基石Class类:java中的各个java类属于同一类事物。描述这类事物的java类的名字就叫做Class。那么,这个类中会有哪些东西呢?
getName() getMethods() getMehhod(String name,Class<?>…parameterTypes) getModifiers() getPackage() getInterfaces() isPrimitive()
Class cls=字节码; 讲一个类加载进内存时,就会在内存中加载进该类的字节码,该字节码就是一个Class类的实例对象
得到Class对象的三个方法
1类名Class cls1=Person.cjass;
2对象Class cls2=p1.getClass();
3Class.forName(“java.lang.String”);//有两种加载方法,一种就是该字节码已经加载进内存,就直接用就好,另外一种就是内存中还没有加载该字节码,那么用类加载器加载进内存
八个基本数据类型有其字节码即Class对象,以及void字节码对象。
int.class==Interger.TYPE TRUE
注意:判断数组类型的Class实例对象使用的方法是 Class.isArray();总之,只要是在源程序中出现的类型,都有其Class实例对象
Constructor类 代表某个类中的构造方法
Constructor[] constructors=Class.forName(“java.lang.String”).getConstructors();
Constructor constructor=
Class.forName(“java.lang.String”).getConstructor(要找的构造方法的参数类型对应的类对象);
Constructor constructor1=
Class.forName(“java.lang.String”).getConstructor(StringBuffer.class); 根据参数类型的到对应的构造方法
construction1.newInstance(new StringBuffer(“abc”) ); 利用得到的构造函数(传入已知的参数)得到实例对象
以上步骤就是 class—constructor—new Object
Class.newInstance() 该方法内部先得到默认的构造方法,然后用该构造方法去创建实例对象。其实在该方法内部是用了缓存机制来保存默认构造方法的实例对象
File类代表某个类中的成员变量
ReflectPoint pt1=new ReflectPoint(3,5);
Field fieldY=pt1.getClass().getFile(“y”); //通过变量名得到字段的字节码。但是不能得到私有的变量。不同对象得到的也是同一个对象 。是类上的变量,要用它去取对象上对应的值
fieldY.get(pt1) 得到指定对象的变量的值
特殊方法pt1.getClass().getDeclaredFile(“y”) 得到所有声明过的变量。包括私有
但是,fieldY.get(pt1) 这个方法不能得到值 不能访问
应对就是 lieldX.setAccessible(true); fieldY.get(pt1) 暴力访问
fileY.getType()得到该字段的类型
fieldY.set(对象,新值)设置某个对象在该字段上新值
Method类 代表某个类中的一个成员方法
String.getMethod(“方法名”,Class<?>…指定方法的参数列表)
.invoke(对象,参数) //将用反射得到的方法操作于这个对象
如果该方法是静态方法的时候,那么调用的对象就可以是null
数组的反射
具有相同维数和元素类型的数组就属于同一个类型,即具有相同的Class实例对象
代表数组的Class是对象的getSuperclass()方法返回的父类为Object类对应的Class
基本数据类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用。
非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
ArrayList HashSet 的比较以及Hashcode
ArrayList中的元素可以重复的。其中存放的是内存地址值
HashSet中的元素不可以重复,重复的元素不能放进该集合中,而不是会覆盖。其保持唯一性的依据是equals方法和Hashcode方法。Hashcode方法。将集合分成若干个区域,每一个元素都会对于一个哈希值,根据值得不同将元素放进应对于的区域中区。当我们要查找某一个对象的时候,根据对象的值到相应的区域中区。为了让相同的对象存放到同一个区域中去,所以就有这样一个说法,就是当两个对象的equals方法相等后,就要让他们的哈希值也是相等的。当一个对象呗存进HashSet集合中去后,就不要修改这个对象中的那些参与计算哈希值的字段了,否则,对象被修后的哈希值与最初的哈希值不同,在这种情况下,即使在contains方法使用该对象的当前引用作为参数去集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删去当前对象,从而造成内存泄露。
反射的作用————>实现框架功能
框架就是在后期的具体内容还没有出现的时候就先引用其。因为在才写程序的时候无法知道要被调用的类名,所以,在程序组无法直接new某一个类的是对象,就要用到反射的方式来做。
框架与工具类有区别的,工具类被用户调研,而框架是调用用户提供的类。
类加载器:将.class文件记载进内存。同时,还提供另一个功能就是在classpath路径下将配置文件加载进内存
InputStream ips=类名.class.getClassLoder.getResourceAsStream(“文件名”)
InputStream ips=类名.class.getResourceAsStream(“文件名”)可以是相对路径也可以是绝对路径。带/开始的话,就是要写绝对路径从classpath的根目录开始加载
内省(introSpector)——>引出JavaBean(特殊的java类,其方法符合固定的规则)
JavaBean是一个特殊的java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,切方法名符合某种命名规则。
如果在两个模块中传递多个信息,可以将这些信息封装到一个JavaBeam中,这种JavaBean的实例对象通常称为值对象(ValueObject)这些信息在类中是用私有的字段来存储的,如果读取或这只致谢字段的值,则需要通过一些专有的方法来访问。
例子:获得一个对象的指定属性名的属性值
对象: ReflectPoint pt1=new ReflectPoint(3,5);
获得名为x的属性的值:String propertyName=”x”;
获得javaBean的属性
PropertyDescriptor pd=new PropertyDescriptor(propertyName,pt1.getClass());
获得x属性的读方法 Method methodGetX=pd.getReadMethod();
获得该对象中x属性的值
设置值 为7 Method methodSetX=pd.getWriteMethod();
methodGetX.invoke(pt1,7)
可以将上述方法应用编译工具向上抽取成方法,提高代码的复用性
另外一种方法 调用IntroSpector.getBeanInfo的方法,得到的BeanInfo对象封装了把这个类当做JavaBean来看的结果信息
使用BeanInfo的方法getPropertyDescriptors();得到所有的属性。然后使用高级for循环来遍历集合,获得所需的属性。
在后期,使用BeanUtils工具包操作JavaBean
首先呀要将该jar包倒进eclipse:在工程目录下新建已经饿lie文件夹,将jar包考进该问该文件夹目录下。然后再该jar包上点击右键 buildpath 再选择addtobuildpath
BeanUtils.setProperty(对象,“属性名称”,“设置值“)//此设置值得类型会装换成字符串类型
而且属性还支持属性链的
PropertyUtils.setProperty(对象,“属性名称”,设置值)
基本注解:1.5新特性 Annotation
注解的引入 如果使用一个过时的方法是编译器会提示。此时如果想去掉这个过时的提醒,就在方法的前面加上注解@SuppressWarnings(“deprecation”) 这个注解其实是一个注解类的实例对象
在一个方法的其那面加上@Deprecated 就是表示这个方法已经过时但是还是可以使用的。
在复写父类方法的时候,要和父类同样的参数类表,那么为了避免错误,可以使用一个注解
告诉编译器要写一个父类的复写方法。当复写出现问题的时候,编译器就会报错。这个注解就是@Override
注解类---应用了“注解类”的类----对“应用了注解类的类”进行反射操作的类
在java中新建一个注解类。可以用反射的方法来检查一个注解是否应用了某一个类
.class.isAnnotationPresent(注解类.class)
也是可以得到该注解getAnnotation(.class)
源注解就是为注解添加的注解
@Retention(RetentionPolicy.RUNTIME)
public @iterrface IycastAnnotion{}
@Retention注解的生存周期有三个阶段:RetentionPolicy.SOURCE RetentionPolicy.CLSAA(默认值) RetentionPolicy.RUNTIME 点分别对象的是 java源文件 class文件 内存中的字节码文件
@Target({ElementType.METHOD, ElementType.TYPE})
该注解指定注解的目的,接受的参数是一个数组。现在写的这个注解目的可以是方法上和类接口以及枚举上
为注解添加属性:注解很像接口,所以其属性很像方法。在调用该方法的时候就可以为其设置属性值。获取属性值要已方法的方式获取 color=“red” .color()=?
当只有一个属性值的时候,可以直接写值、一个属性可以有省缺值default“”;
*当数组属性中的元素只有一个的时候,可以省略{}
还可以有枚举和注解以及Class类型的属性值
泛型:是给javac编译器使用的,可以限定集合的输入类型。编译器编译带类型说明的集合会去掉类型信息,是程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译器的字节码会去掉泛型的类型信息,只要跳过编译器,就可以往某个泛型集合中加入其它类型的数据。例如,用反射得到集合,在调用add方法即可
Collection<String> collection=new ArrayList<String>;
collection.getClass().getMethod(“add”,Object.class).invoke(collection,1);
参数化类型不考虑类型参数的继承关系
使用?通配符可以引用其它各种类型化的类型。?通配符定义的变量的主要用作引用,可以调用与参数无关的方法,不能调用与参数有个的方法
通配符的拓展 限定上下限
举例:定义一个方法实现交换数组任意两个位置的元素(但是只有引用类型才能作为泛型的实际参数)
private static <T> void swap(T[] a,int i,int j)
{
T temp=a[i];
a[i]=a[j];
a[j]=temp;
}
类也可以定义为泛型。静态方法不能应用类的泛型类型。但是,可以静态方法自己定义一个泛型。
类加载器:java虚拟机有多个加载器。系统默认三个主要的加载器。但一个类被调用的时候,类加载器就会将该类的字节码加载进内存。
每个类加载器加载特点位置的类:BootStrap ExtClassLoder AppClassLoder
得到一个类的类加载器的名字
类名.class.getClassLoder().getClass().getName();
当虚拟机要加载一个类时,会先派当前线程的类加载器去加载线程中的第一个类。如果类a中引用了类b,java虚拟机将使用加载类a的加载器来加载类b。还可以直接调用ClassLoder.lodeClass()方法来指定摸个类加载器去加载某个类
委托加载机制:类加载器加载到类时,会先委托其上级加载器,每一个加载器都是这样,直到祖宗类加载器。当所有祖宗类加载器没有加载大类,回到发起者加载器,还加载不了,则抛出ClassNotFindException,不再去找发起者加载器的儿子,因为没有getChile方法。
代理:要为以存在的多个具有相同接口的目标类的各个方法增加一些系统功能。代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
如果采用工程模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类还是代理了,这样以后很容易切换,譬如,想要日志功能是就配置代理类,否则目标类,这样增加系统功能就很容易,运行一段时间后,又想去掉系统功能也容易
AOP aspect oriented program 面向方面的编程。系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面。安全。事物、日志等功能要贯穿到好多个模块当中去,所以,他们就是交叉业务。
动态代理技术:jvm可以在运行时期动态生成出类的字节码,这种动态生成的类往往笨哦用作代理类,即动态代理类。
jvm生成的动态代理类必须实现一个或者多个接口,所以,jvm生成的动态类只能作用具有相同接口的目标类的代理。CGLIB库可以动态的生成一个类的子类,一个类的子类也可以用做该类的代理,所以,如果要为一个没有实现接口得类生成动态代理类,那么可以使用CGLIB库
代理类的各个方法中通常除了要调用奴婢的相应方法和对我返回目标返回的结果外,还可以在代理方法中的四个位置加上系统功能代码:
1 在调用目标方法之前 2 在调用目标方法之后 3在调用目标方法的前后
4在处理目标方法异常的catch块中
---------------------- ASP.Net+Android+IOS开发、 .Net培训、期待与您交流! ----------------------