-------android培训java培训期待与您交流!----------
静态导入
-
import static
:导入一个类中的某个静态方法或所有静态方法。如:import static java.lang.Math.max;
,导入的是Math下的max方法。
package com.sergio.NewTecl;
//静态导入包中的所有静态方法
import static java.lang.Math.*;
//静态导入包中某个静态方法
//import static java.lang.Math.max;
/**
* 静态导入例子
* Created by Sergio on 2015-06-03.
*/
public class ImportStatic {
public static void main(String[] args) {
System.out.println(max(3, 7));//求租嗲之
System.out.println(abs(4 - 3));//求绝对值
}
}
可变参数
- 只能出现在参数列表的最后;
-
...
位于变量类型和变量名之间,前后有无空格都可以; - 调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
package com.sergio.NewTecl;
/**
* 可变参数
* Created by Sergio on 2015-06-03.
*/
public class VariableParam {
public static void main(String[] args) {
System.out.println(add(3, 6));
System.out.println(add(3, 1, 93, 23));
}
public static int add(int x, int... args) {
int sum = 0;
for (int i = 0; i < args.length; i++) {
sum += args[i];
}
return sum;
}
}
foreach
- 语法:
for(type 变量名:集合变量名){...}
- 注意事项:迭代变量必须在()中定义;集合变量可以是数组或实现了Iterable接口的集合类。
package com.sergio.NewTecl;
/**
* foreach
* Created by Sergio on 2015-06-03.
*/
public class ForEach {
public static void main(String[] args) {
int[] buf = new int[] {3, 5, 6, 4, 2, 8};
int sums = 0;
for (int sum : buf) {
sums += sum;
}
System.out.println(sums);
}
}
自动装箱拆箱
- 基本数据类型封装成引用数据类型。
- 引用数据类型拆箱成基本数据类型。
基本数据类型 | 引用数据类型 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
boolean | Boolean |
float | Float |
double | Double |
char | Character |
- 注意:在基本数据类型的范围类,装箱成引用数据类型的两个对象引用相同值,他们两个对象的值是相等的。
- 共享设计模式:避免大量拥有相同内容的小类的开销,使大家共享一个类(元类)。
package com.sergio.NewTecl;
/**
* 装箱与拆箱
* Created by Sergio on 2015-06-03.
*/
public class AutoBox {
public static void main(String[] args) {
Integer i = 2;//装箱
Integer i2 = 4;
System.out.println(i + i2);//拆箱
Integer i3 = 12;
Integer i4 = 12;
//在int范围内,i3和i4对象引用的值相等
System.out.println(i3 == i4);
Integer i5 = 138;
Integer i6 = 138;
//超出了int范围,i5和i6的引用值不相等。
System.out.println(i5 == i6);
}
}
枚举
- 让某个类型的变量的取值只能为若干个固定值中的一个。
package com.sergio.NewTecl;
/**
* 枚举应用示例
* Created by Sergio on 2015-06-04.
*/
public class EnumTest1 {
public static void main(String[] args) {
WeekDay weekDay = WeekDay.FRI;
System.out.println(weekDay.name());//枚举对象的名字
System.out.println(weekDay.ordinal());//排列位置,从0开始
System.out.println(WeekDay.valueOf("SUN"));//将字符串转成枚举对象
System.out.println(WeekDay.values());//获得枚举元素的转化成数组
}
public enum WeekDay {
SUN, MON, TUE, WED, THI, FRI, SAT
}
}
- 构造方法枚举
public enum WeekDay {
SUN(2), MON(), TUE, WED, THI, FRI, SAT;//枚举的元素相当于枚举类型的对象,
// 初始化时可以按照参数构造方法带入
//空构造方法
private WeekDay() {
System.out.println("first");
}
//带参数构造方法
private WeekDay(int day) {
System.out.println("second");
}
}
- 抽象方法枚举
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 long time;
//枚举元素子类对象的构造方法
private TrafficLamp(long time){
this.time = time;
}
}
内省与JavaBean
- 内省:IntroSpector。主要用于操作JavaBean。
- JavaBean:特殊的Java类,类中的方法名称符合某种约定的规则。如:
getAge()
、setAge(int age)
像这种方法名称前面是get和set打头的规则的类这种方式叫做JavaBean,主要用于访问Java类中的私有字段。JavaBean的属性根据set和get方法名称来获知,如setAge
,属性就为age
,而并不是跟类的成员变量有关,看不到Java类的内部成员。 - 两个模块间传递多个信息就是用JavaBean的方式,将这些信息封装到一个JavaBean中,这种JavaBean的实例对象称之为值对象(Value Object)。这些类中用私有字段存储,可以用
set
和get
的方法来获取或者设置这些值。
package com.sergio.NewTecl;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 内省的操作
* Created by Sergio on 2015-06-08.
*/
public class JavaBeanDemo1 {
public static void main(String[] args) throws Exception {
JavaBeanTest jbt = new JavaBeanTest(3, 5);
//要获取的JavaBean属性X
String propertyName = "x";
//获取JavaBean信息,get
PropertyDescriptor pd = new PropertyDescriptor(propertyName, jbt.getClass());
Method methodGetX = pd.getReadMethod();
Object objValue = methodGetX.invoke(jbt);
System.out.println(objValue);
//set
Object value = 4;
Method methodSetX = pd.getWriteMethod();
methodGetX.invoke(jbt, value);
System.out.println(jbt.getX());
}
}
class JavaBeanTest {
private int x;
public int y;
JavaBeanTest(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
BeanUtils
- 对JavaBean操作的封装工具类。
//BeanUtils主要操作的值为字符串
BeanUtils.getProperty(jbt, "x");
BeanUtils.setProperty(jbt, "x", "9");
//Map与BeanUtils的互操作。BeanUtils为值对象,而Map为键值对
Map map = new HashMap();
BeanUtils.setProperty(map, "name", "lisi");
//PropertyUtils操作的本身的数据类型
PropertyUtils.setProperty(jbt, "x", 9);
注解
- 注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,javac编译器,开发工具和其他程序可以用反射来获取你写的类及各种元素上有无标记,根据获取到的标记去做相应的工作。
- 标记可以加在包、类、字段、方法,方法的参数以及局部变量上。
- @SuppressWarnings:阻止编译器的警告。@Deprecated:标记某个过时的类或方法。@Override:重载。
-
注解相当于一个你的源程序中要调用的一个类,要在源程序中应用某个注解,得先定义这个注解类。就像调用某个类类似,你的先开发好这个类。
- @Retention元注解:类的保留生命周期阶段。取值为:RetentionPolicy.SOURCE、RetentionPolicy.Class(默认值)、RetentionPolicy.RUNTIME代表调用的生命周期。分别对应注解三个周期:java源文件->class文件->内存中的字节码
- @Target元注解:注解的类可以作用在那个成分上(类、方法、接口等)。
- 注解属性:注解相当于独特的类,而属性相当于这个类中的方法。定义方式:在注解中增加
String color();
、@MyAnnotation(color="blue")
- 数组类型的属性:int arrayAttr default {2,4};@MyAnnotation(arrayAttr={2,3,4})\如果数组属性只有一个元素,这时候属性值的部分可以省略大括号。
- 枚举的属性:EnumTest1.TrafficLamp lamp();@MyAnnotation(lamp=EnumTest1.TrafficLamp.GREEN)。
- 注解属性:MetaAnnotation annotationAttr() default 。@MetaAnnotation("2");@AnnotationDemo(annotationAttr = @MetaAnnotation("hz"), color = "red", value = "12", arrayAttr = {2, 3, 4})。
package com.sergio.NewTecl;
/**
* 注解定义
* Created by Sergio on 2015-06-09.
*/
public @interface MetaAnnotation {
String value();
}
============================
package com.sergio.NewTecl;
/**
* 注解定义
* Created by Sergio on 2015-06-09.
*/
public @interface MetaAnnotation {
String value();
}
=====================
package com.sergio.NewTecl;
/**
* 注解与反射
* Created by Sergio on 2015-06-09.
*/
@AnnotationDemo(annotationAttr = @MetaAnnotation("hz"), color = "red", value = "12", arrayAttr = {2, 3, 4})
public class AnnotationTest {
//阻止编译器过时API警告
@SuppressWarnings("deprecation")
@AnnotationDemo(value = "23")//此注解color已经有了默认值,只需设置value即可
public static void main(String[] args) {
System.runFinalizersOnExit(true);//过期API
if (AnnotationTest.class.isAnnotationPresent(AnnotationDemo.class)) {
AnnotationDemo annotation =
(AnnotationDemo) AnnotationTest.class.getAnnotation(AnnotationDemo.class);
System.out.println(annotation.color());
System.out.println(annotation.value());
System.out.println(annotation.arrayAttr().length);
System.out.println(annotation.lamp().nextLamp().name());
System.out.println(annotation.annotationAttr().value());
}
}
}
泛型
- JDK1.5出现的新特性,解决了安全问题,是一个类型安全机制。使用泛型集合,可以将一个集合的元素作为特定的类型,集合中只能存储同一个类型的对象,这样更安全;获取对象时,不需要做强制类型转换方便。
- 定义格式:
ArrayList
。collection = new ArrayList (); <>
此符号主要用来定义要确认的类型。 - 去类型化:编译器生成的集合字节码会去掉泛型类型信息。
- 术语:ArrayList
泛型类型、ArrayList 中的E称为类型变量或类型参数。 - 泛型兼容性:
Collection
可以兼容;c = new Vector(); Collection c = new Vector
可以兼容。(); - 泛型的参数化类型没有继承关系:
Vector
错误。v = new Vector -
Collection> collection
:此处的?是通配符,表示任意类型。 - 泛型通配符上限:
Vector extends Number> x = new Vector
,表示通配符的类型是Number或者Number的子类。() - 泛型通配符下限:
Vector super Integer> = new Vector
,表示通配符类型是Integer或Integer的父类。()
package com.sergio.NewTecl;
import java.util.ArrayList;
import java.util.Collection;
/**
* 泛型基础信息介绍
* Created by Sergio on 2015-06-11.
*/
public class GenericDemo {
public static void main(String[] args) throws Exception {
//定义String类型的集合
ArrayList collection1 = new ArrayList();
collection1.add("abc");
System.out.println(collection1.get(0));
ArrayList collection2 = new ArrayList();
//判断这两个对象的的字节码是否一样。结果是true,说明字节码一样,编译器生成的字节码会去掉类型信息
System.out.println(collection1.getClass() == collection2.getClass());
//使用反射往集合中添加String字符串内容
collection2.getClass().getMethod("add", Object.class).invoke(collection2, "abc");
System.out.println(collection2.get(0));
printCollection(collection2);
}
//打印集合元素。此处的?是通配符,表示任意类型
public static void printCollection(Collection> collection) {
for (Object obj : collection) {
System.out.println(obj);
}
}
}
package com.sergio.NewTecl;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 对集合进行迭代
* Created by Sergio on 2015-06-11.
*/
public class GenericDemo1 {
public static void main(String[] args) {
HashMap aMaps = new HashMap();
aMaps.put("zhansan", 23);
aMaps.put("lisi", 43);
Set> entrySet = aMaps.entrySet();
for (Map.Entry entry : entrySet) {
System.out.println(entry.getKey() + ":::" + entry.getValue());
}
}
}
- 异常中使用泛型:
public sayException() throws T {
try {
} catch (Exception e) {
throw (T) e;
}
return;
}
泛型类型推断:
根据调用泛型方法时实际传递的参数类型或返回值的类型来对端:
- 当某个类型变量只在整个参数列表中的所有参数和返回值的一处被应用了,那么根据调用方法时该处的实际应用类型来确定,及直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型。如:
swap(new String[3], 3,4) -> static
。void swap(E[] a, int i, int i) - 当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用调用方法时这多处的实际应用类型都对应同一种类型来确定。如:
add(3, 5) -> static
。T add(T a, T b) - 当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型,且没有使用返回值,这时候去多个参数中的最大交集类型,如下面这句实际对应类型是Number,编译没有问题,只是运行时出问题:
fill(new Integer[3], 3, 5) -> static
。void fill(T[] a, T v) - 当某个性类变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同类型,并且使用返回值,这时候优先考虑返回值的类型,例如:这面这句实际对应的类型是Integer,编译报告错误,将变量x的类型改为Number,则没有了错误,
int x -(3, 3.5f) -> static
。T add(T a, T b) - 参数类型的类型推断具有传递性,下面第一种情况推断实际参数类型为Object,编译没问题,而第二种情况则根据参数化的Vector类实例类型变量直接确定为String类型,编译将出现问题:
copy(new Integer[5], new String[5]) -> static
。void copy(T[] a, T[] b)
泛型的类和方法定义
- 泛型类何时定义:当类中操作的引用数据类型不确定的时候,可以用泛型来完成扩展。
- 定义泛型类和方法:
{} public
。定义泛型类的类型,在整个类中有效,如果被方法调用,那么泛型类的对象明确药操作的具体类型后,所有操作的类型就已经固定了,为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将方法定义在方法上。T findByID(int id) - 静态方法类型:静态方法不可以访问类型定义的泛型,如果静态方法操作的数据类型不确定,可以将泛型定义在方法上。
public staitc
void method(E e){} - 注意:在对泛型类型进行参数化时,类型参数的实例化必须是引用类型,不能是基本类型。当一个变量被声明为泛型时,只能被实例变量、方法和内部类调用,而不能被静态变量和静态方法方法调用,因为静态成员是被所有参数化的类型所共享,所以静态成员不应该有类级别的类型参数。
- 泛型接口:
package com.sergio.NewTecl;
/**
* 泛型接口
* Created by Sergio on 2015-06-12.
*/
interface Inter {
void show(T t);
}
//实现接口
class InterImpl implements Inter {
public void show(R r) {
System.out.println("show::" + r);
}
}
类加载器
- 加载类的工具。将.class加载进JVM中然后进行处理。
- Java虚拟机有多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap、ExtClassLoader、AppClassLoader。
- BootStrap:类加载器也是Java类,而必须有一个类加载器不是Java类,而这正是BootStrap,嵌入在JVM里。
- ExtClassLoader:主要加载具有父子关系的树状组织的对象如继承关系的类,加载父级的对象。
-
AppClassLoader:系统Java类加载器。
类加载器的委托机制
- 当Java虚拟机要加载一个类时,有那个类加载器加载的情况如下:首先当前线线程的类加载器去加载线程中的第一个类;如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B;还可直接调用ClassLoaderClass()方法来制定某个类加载器去加载某个类。
- 每个类加载器加载类时,优先委托给上级类加载器(如上面提到的BootStrap->ExtClassLoader->AppClassLoader优先级从左到右降低)。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,就抱ClassNotFoundException异常。
- 获取类加载器名字:被加载器类.class.getClassLoader().getClass().getName()
- 自定义类加载器必须要继承ClassLoader,并且实现
findClass(String name)
方法,使用指定的二进制名称查找类。
代理类
- 为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如:异常处理、日志、计算方法的运行时间、事务处理等等,这些功能可以通过代理来解决。编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加载系统功能的代码。
目标类:doSomeThing(){
业务功能代码
}
代理类:doSomeThing(){
//前置系统功能代码
目标对象.doSomeThing()
//后置系统功能代码
}
AOP:系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面,交叉业务的编程问题即为面向方面编程,而代理就是来处理此问题。
动态代理技术:要为系统中各种接口的类增加代理功能,需要太多的代理类,而这时候可以通过JVM可以在运行期动态生成出类的字节码,而这可以被用作代理类,即为动态代理类。如果要动态生成代理类,而目标类没有实现接口,可以通过CGLIB第三方类库来生成,
package com.sergio.NewTecl;
import javax.xml.bind.SchemaOutputResolver;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
/**
* 创建动态类及查看其构造方法和成员方法列表信息
* Created by Sergio on 2015-06-14.
*/
public class ProxyTest {
public static void main(String[] args) throws Exception {
//获取代理类的字节码
Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy.getName());
//构造方法
Constructor[] constructors = clazzProxy.getConstructors();
for (Constructor constructor : constructors) {
//获取构造方法名称
String name = constructor.getName();
StringBuilder stringBuilder = new StringBuilder(name);
stringBuilder.append('(');
Class[] clazzParams = constructor.getParameterTypes();
for (Class clazzParam : clazzParams) {
stringBuilder.append(clazzParam.getName()).append(',');
}
if (clazzParams != null && clazzParams.length == 0) {
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
}
stringBuilder.append(')');
System.out.println(stringBuilder.toString());
}
//方法
Method[] methods = clazzProxy.getMethods();
for (Method methodor : methods) {
//获取构造方法名称
String name = methodor.getName();
StringBuilder stringBuilder = new StringBuilder(name);
stringBuilder.append('(');
Class[] clazzParams = methodor.getParameterTypes();
for (Class clazzParam : clazzParams) {
stringBuilder.append(clazzParam.getName()).append(',');
}
if (clazzParams != null && clazzParams.length == 0) {
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
}
stringBuilder.append(')');
System.out.println(stringBuilder.toString());
}
System.out.println("开始创建实例对象");
//获得构造方法,主要是现实InvocationHandler是个接口,调用处理处理程序
Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);
//需要实现invocationHandler的接口方法,invoke接受的三个参数为:代理对象,代理对象的那个方法,代理对象方法的参数
class MyInvocationHander1 implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
//动态创建代理对象
Collection proxy1 = (Collection) constructor.newInstance(new MyInvocationHander1());
proxy1.clear();//调用collection中的clear方法
proxy1.size();
//创建实例的第二种写法
Collection proxy2 = (Collection) constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
//动态创建实例对象第三种写法,
Collection proxy3 =
(Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),
new Class[] {Collection.class},
new InvocationHandler() {
ArrayList target = new ArrayList<>();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long beginTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + "所用时间" + (endTime - beginTime));
return retVal;
}
});
proxy3.add("xyz");
proxy3.add("lhm");
System.out.println(proxy3.size());
}
}