Java基础总结
以下笔记整理自张孝祥老师的《Java高新技术》视频教程
01 枚举
public class EnumTest {
public static void main(String[] args) {
WeekDay weekDay2 = WeekDay.FRI;
System.out.println(weekDay2);
System.out.println(weekDay2.name());
System.out.println(weekDay2.ordinal()); //排序从零开始
System.out.println(WeekDay.valueOf("SUN").toString());
System.out.println(WeekDay.values().length);
new Date(300){//覆写父类方法};
}
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");}
}
public enum TrafficLamp{
//每个成员都是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 int time;
private TrafficLamp(int time){this.time = time;}
}
}
02 反射
反射就是把Java类中的各种成分映射成相应的Java类
注意:反射Constructor、Field:
- ∵方法和属性都是对象的,∴要得到属性值、更改属性值、调用用方法是要传入具体的对象
- 调用静态方法时对象传入null即可
反射获取泛型参数类型
public class GenericTest {
public static void main(String[] args) throws Exception {
...
//Vector<Date> v1 = new Vector<Date>();
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()[0]); //实际类型参数:Date
}
public static void applyVector(Vector<Date> v1){
}
}
获取父类泛型的实际参数类型
public abstract class DaoSupportImpl<T> implements DaoSupport<T> {
private Class<T> clazz;
public DaoSupportImpl() {
// 得到T的真实类型
// this表示当前new的对象实例.
// getGenericSuperclass()表示获取对象的泛型的父类的类型信息;即DaoSupport<T>
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
this.clazz = (Class) pt.getActualTypeArguments()[0]; // 获取真实类型信息
System.out.println("-----> clazz = " + clazz);
}
}
得到类的字节码对象 Class
注意:
用类来得到Class,用.class
用对象来得到Class,用getClass()方法
用完整类名来得到Class,用Class.forName(“...”);
Person p = new Person();
- Class c1 = Person.class [1]
- Class c2 = p.getClass() //用对象来得到Class
- Class c3 = Class.forName(“com.ttino.model.Person”);
- Android中的方法,仅参考
private void getCacheSize(PackageInfo packageInfo) {
try {
Class<?> clazz = getClassLoader().loadClass("packageManager");
//通过反射获取到当前的方法
Method method = clazz.getDeclaredMethod("getPackageSizeInfo",
String.class,IPackageStatsObserver.class);
} catch (Exception e) {
e.printStackTrace();
}
}
有9个预定义的Class对象 :8个基本类型 + void (void.class)
**int.class.isPrimitive(); ** //true;是否是原始(基本)类型 的字节码
**int[].class.isArray(); ** //true; 判断Class是否是数组
java四类八种基本数据类型:
第一类:整型 byte short int long
第二类:浮点型 float double
第三类:逻辑型 boolean(它只有两个值可取true false)
第四类:字符型 char
反射构造方法Constructor
反射字段Filed
/**
* 将一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"
*/
Object obj = Class.forName("...").newInstance();
Field[] fields = obj.getClass().getDeclaredFields();
for(Field f : fields){
if(f.getType() == String.class){ //字节码用==来比较,因为只有一份
f.setAccessible(true);
String newValue = ((String)f.get(obj)).replace('b', 'a');
f.set(obj, newValue);
}
}
System.out.println(obj);//覆写了obj的toString()方法
反射方法Method
//兼容jdk1.4,在1.5中的写法
//方法一:让1.5编译器去拆,拆除来的就是Object
//mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
//方法二:告诉1.5的编译器不要拆
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
数组反射
维度和类型都相同的数组,class是同一种类型
数组和Object的对应关系:
int [] a1 = new int[]{1,2,3};
int [] a2 = new int[4];
int[][] a3 = new int[2][3];
String [] a4 = new String[]{"a","b","c"};
Object aObj1 = a1;
Object aObj2 = a4;
//Object[] aObj3 = a1;//a1数组里装的是int, int(基本类型)不是Object, Integer(对象包装类)是
Object[] aObj4 = a3;//数组里装的是数组,数组的父类是Object[a1.getClass().getSuperclass().getName()]
Object[] aObj5 = a4;//数组里装的是String,String是Object
打印数组里的内容:
//整数不会转为List中的元素
System.out.println(Arrays.asList(a1));//[[I@4e25154f]
System.out.println(Arrays.asList(a4));//[a, b, c] //String转了
asList(T...a) //1.5 // List<String> stooges =
Arrays.asList("Larry", "Moe", "Curly");
asList(Object[] o)//1.4
反射数组的长度和内容,用Array类
private static void printObject(Object obj) {
Class clazz = obj.getClass();
if(clazz.isArray()){
int len = Array.getLength(obj);//长度
for(int i=0;i<len;i++){
System.out.println(Array.get(obj, i));//内容
}
}else{//如果不是数组,直接打印
System.out.println(obj);
}
}
03 框架与工具类
- 开发商卖给你房子,你装上自己的门,买了把锁
框架:开发商提供的房子,可以卖给任何人
自己的类:门看成是自己的做的,用户将门装在房子中
工具类:锁看成是买的别人的,锁被门调用
- 框架调用用户提供的类,工具类被用户调用
04 类加载器
- 最直接的方式
InputStream ips = new FileInputStream("config.properties");
- 用Class得到类加载器getClassLoader().getResourceAsStream。默认从classpath(编译好的.class文件的存放路径)根目录下查找文件
注意:路径前面不加/
InputStream ips = ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");
- 直接用Class的getResourceAsStream()
- 3.1、如果不用/开头,默认从ReflectTest2.class所在目录下开始查找 [相对路径]
InputStream ips = ReflectTest2.class.getResourceAsStream("config.properties");
- 3.2、如果用/开头,绝对路径查找
InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
4.示例
InputStream ips = ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");
Properties props = new Properties();
props.load(ips);
//这里释放的是对象关联的系统资源,不是对象本省,ips对象由JVM管理
ips.close();//释放对象关联的系统资源,否则会有内存泄露
String className = props.getProperty("className");
Collection collections = (Collection)Class.forName(className).newInstance();
05 内省(Introspector)操作JavaBean
//ReflectPoint pt1 = new ReflectPoint(3,5); //JavaBean
//String propertyName = "x";
//getProperty(pt1, propertyName);
private static Object getProperty(Object pt1, String propertyName)throws Exception {
/*
//方式一
PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());//传入属性名和Class
Method methodGetX = pd.getReadMethod();
Object retVal = methodGetX.invoke(pt1);
*/
//方式二
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor pd : pds){
if(pd.getName().equals(propertyName)) {
Method methodGetX = pd.getReadMethod();
retVal = methodGetX.invoke(pt1);
break;
}
}
return retVal;
}
06 BeanUtils操作JavaBean
copyProperties():将一个对象的属性复制到另一对象
descirble():将JavaBean转为map
populate():将map的内容填充到JavaBean
ReflectPoint pt1 = new ReflectPoint(3,5);
//BeanUtils set时会以String类型来set;get时会以String类型来返回
//参数:对象、属性名
BeanUtils.getProperty(pt1, "x").getClass().getName();//java.lang.String;实际上x是int型
//参数:队形、属性名,值
BeanUtils.setProperty(pt1, "x", "9");
/*
//java7的新特性
Map map = {name:"zxx",age:18};
BeanUtils.setProperty(map, "name", "lhm");
*/
//级联属性
BeanUtils.setProperty(pt1, "birthday.time", "111");
System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));
//PropertyUtils操作JavaBean
//操作时,注意类型要与属性字段的类型对应
PropertyUtils.setProperty(pt1, "x", 9);
System.out.println(PropertyUtils.getProperty(pt1, "x").getClass().getName());//java.lang.Integer
07 注解
@SuppressWarnings(“deprecation”):取消警告 //source阶段,编译器用完了(编译成.class)就没用了
@Deprcation:过时 //runtime阶段,编译器是通过读类二进制来检查某个方法是否过期
@Override:覆写 //source阶段
注解应用:3个类
注解类 + 应用了“注解类”的类 + 对‘应用了“注解类”的类’进行反射操作的类
//SOURCE、CLASS、RUNTIME分别对应的注解生命周期:java源文件class文件内存中的字节码。默认CLASS
@Retention(RententionPolicy.RUNTIME)//保留到运行期间[元注解];或(value=”RUNTIME”)
//@Target({ElementType.METHOD,ElementType.TYPE}) //只能放在方法和类型上
public @interface ItcastAnnotation {}
元注解:为注解服务的注解
元数据:数据的数据
原信息:信息的信息
注解类:
EnumTest类参考枚举
ItcastAnnotaion.java
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface ItcastAnnotation {
String color() default "blue";
String value();
int[] arrayAttr() default {3,4,4};
EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;
MetaAnnotation annotationAttr() default @MetaAnnotation("lhm");
}
MetaAnnotaion.java
public @interface MetaAnnotation {
String value();
}
应用了“注解类”的类,其中Main方法暂作为“对注解进行解析”的代码存放处
@ItcastAnnotation(annotationAttr=@MetaAnnotation("flx"),color="red",value="abc",arrayAttr=1)
public class AnnotationTest {
@SuppressWarnings("deprecation")
@ItcastAnnotation("xyz")
public static void main(String[] args) throws Exception{
System.runFinalizersOnExit(true);//测试@suppressWarnings注解
//如果AnnotionTest类上存在ItcastAnnotation注解
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
ItcastAnnotation annotation = (ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.color());//red
System.out.println(annotation.value());//abc
System.out.println(annotation.arrayAttr().length);//1
System.out.println(annotation.lamp().nextLamp().name());//GREEN
System.out.println(annotation.annotationAttr().value());//flx
}
//获取Main方法上的注解
Method mainMethod = AnnotationTest.class.getMethod("main", String[].class);
ItcastAnnotation annotation2 = (ItcastAnnotation)mainMethod.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation2.value());//xyz
}
}
08 泛型
泛型是给编译器看的,编译完后不保存泛型的类型
- 整个ArrayList<E> 称为泛型类型
- ArrayList<E>中的E 称为类型变量或类型参数
- 整个ArrayList<Integer> 称为参数化的类型
- ArrayList<Integer>中的Integer 称为类型参数的实例或实际类型参数
- ArrayList<Integer>中的<> 念typeof
- ArrayList 称为原始类型
泛型中的通配符:
?:任意类型
自定义泛型:
1 方法:
1.1、自定义类型T要在返回类型前、紧挨着返回类型声明
1.2、返回类型T推断:取最小公倍数;如果有返回类型,优先考虑返回类型
copy(new Date[], new String[10]);
<T> void copy(T dest, T[] src){}
类型推断有时要考虑<>中的类型传递:
copy(new Vector<String>[], new String[10]);//copy(new Vector<Date>[], new String[10]):错误
<T> void copy(Collection<T> col, T[] arr){}
1.3、泛型T的实际类型只能是引用类型,不能是基本数据类型
private static <T> T add<T x, T y){
return null;
}
限定T
private static <T extends Serializable&Number> T sub(Class<T> clazz){}
泛型异常
private static <T extends Exception > void Say() throws T{
try{}catch(Exception e){throw (T)e}
}
2.类
dao:data access object,数据访问对象
类里面的静态成员不能使用泛型对象
public class GenericDao<T>{
}
09 类加载器
- BootStrap:jre/lib/rt.jar
- |-ExtClassLoader:jre/lib/ext/*.jar
- |-AppClassLoader:classpath下指定的所有jar或目录
- |-MyClassLoader:自定义的特殊目录
- |-AppClassLoader:classpath下指定的所有jar或目录
- |-ExtClassLoader:jre/lib/ext/*.jar
Thread指定类加载器:
ClassLoader getContextClassLoader() 返回该线程的上下文 ClassLoader
void setContextClassLoader(ClassLoader cl) 设置该线程的上下文 ClassLoader
自定义的类加载器加载指定的类:
ClassLoader.loadClass()
类加载器委托加载机制:
父加载器加载 -> 子加载器加载
自定义类加载器
原始类:
public class ClassLoaderAttachment extends Date {
public String toString(){
return "hello,itcast";
}
}
调用类:
public static void main(String[] args) throws Exception {
//加载.class文件
Class clazz = new MyClassLoader("itcastlib").loadClass("cn.itcast.day2.ClassLoaderAttachment");
Date d1 = (Date)clazz.newInstance();
System.out.println(d1);
}
加载器:
public class MyClassLoader extends ClassLoader{
//测试加解密
public static void main(String[] args) throws Exception {
String srcPath = args[0];
String destDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
String destPath = destDir + "\\" + destFileName;
FileOutputStream fos = new FileOutputStream(destPath);
cypher(fis,fos);
fis.close();
fos.close();
}
//加密方法
private static void cypher(InputStream ips ,OutputStream ops) throws Exception{
int b = -1;
while((b=ips.read())!=-1){
ops.write(b ^ 0xff);
}
}
//-------------------功能分割线------------------------
//class文件的目录
private String classDir;
//查找Class
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//文件全名 = 目录 + \ + 名称 + .class
String classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.')+1) + ".class";
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis,bos);
fis.close();
byte[] bytes = bos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public MyClassLoader(){
}
public MyClassLoader(String classDir){
this.classDir = classDir;
}
}
10 代理的概念与作用
JVM代理
三个参数:1、类加载器;2、接口;3、InvocationHandler
Proxy生成的代理类继承了Object的方法:
其中只有hashCode、equals、toString三个方法才交给invocationHandler的invoke去处理,其它方法都有自己的实现
1、分步获取
获取代理类 -> 获取代理类的构造方法 -> 构造方法中传入InvocationHandler来创建实例对象
public class ProxyTest {
public static void main(String[] args) throws Exception{
//0、创建Collection接口的代理类
//参数1:类加载器;参数2:接口
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
//1、打印代理类的名称
System.out.println(clazzProxy1.getName());
//2、获取代理类的所有构造方法
System.out.println("----------begin constructors list----------");
Constructor[] constructors = clazzProxy1.getConstructors();
for(Constructor constructor : constructors){
String name = constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append('(');
Class[] clazzParams = constructor.getParameterTypes();
for(Class clazzParam : clazzParams){
sBuilder.append(clazzParam.getName()).append(',');
}
if(clazzParams!=null && clazzParams.length != 0)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
//3、获取代理类的所有方法
System.out.println("----------begin methods list----------");
Method[] methods = clazzProxy1.getMethods();
for(Method method : methods){
String name = method.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append('(');
Class[] clazzParams = method.getParameterTypes();
for(Class clazzParam : clazzParams){
sBuilder.append(clazzParam.getName()).append(',');
}
if(clazzParams!=null && clazzParams.length != 0)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
//4、创建代理类的实例
System.out.println("----------begin create instance object----------");
//Object obj = clazzProxy1.newInstance();//错误,代理类中没有不带参数的构造方法
//4.1、获取唯一的构造方法
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
//自定义InvocationHandler类
class MyInvocationHander1 implements InvocationHandler{
//参数1:代理对象、参数2:代理对象的某个方法、参数3:方法接受的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHander1());
System.out.println(proxy1.toString());
proxy1.clear();
//proxy1.size(); //invoke返回null,size()要的是整数,null不能转成整数,所以报错
Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
}
}
2、一步到位
Collection proxy3 = (Collection) Proxy.newProxyInstance(
Collection.class.getClassLoader(), // 参数1:ClassLoader
new Class[] { Collection.class }, // 参数2:Class[]
new InvocationHandler() { // 参数3:InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ArrayList target = new ArrayList();
return method.invoke(target, args);
}
});
proxy3.add("111"); Syso(proxy3.size());//0
//原因:每调用一次方法都会去调用InvocationHandler的invoke方法,而每一次都会new一个ArrayList
//可以把ArrayList改成InvoketionHandler的成员变量
3、AOP原理
public class ProxyTest {
public static void main(String[] args) throws Exception{
final ArrayList target = new ArrayList();
Collection proxy3 = (Collection)getProxy(target,new MyAdvice());
proxy3.add("zxx");
proxy3.add("lhm");
proxy3.add("bxd");
System.out.println(proxy3.size());
System.out.println(proxy3.getClass().getName());
}
private static Object getProxy(final Object target,final Advice advice) {
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy3;
}
}
public class MyAdvice implements Advice {
long beginTime = 0;
public void afterMethod(Method method) {
System.out.println("从传智播客毕业上班啦!");
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + " running time of " + (endTime - beginTime));
}
public void beforeMethod(Method method) {
System.out.println("到传智播客来学习啦!");
beginTime = System.currentTimeMillis();
}
}
public interface Advice {
void beforeMethod(Method method);
void afterMethod(Method method);
}
4、Spring的Bean工厂模拟
1、BeanFactory.java
public class BeanFactory {
//加载配置文件
Properties props = new Properties();
public BeanFactory(InputStream ips){
try {
props.load(ips);
} catch (IOException e) {
e.printStackTrace();
}
}
//创建Bean
public Object getBean(String name){//传入name,对象配置文件的xxx
String className = props.getProperty(name);
Object bean = null;
try {//创建JavaBean
Class clazz = Class.forName(className);
bean = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
//如果bean是ProxyFactoryBean,创建代理对象
if(bean instanceof ProxyFactoryBean){
Object proxy = null;
//由ProxyFactoryBean来创建代理对象
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;
try {
Advice advice = (Advice)Class.forName(props.getProperty(name + ".advice")).newInstance();
Object target = Class.forName(props.getProperty(name + ".target")).newInstance();
proxyFactoryBean.setAdvice(advice);
proxyFactoryBean.setTarget(target);
proxy = proxyFactoryBean.getProxy();
} catch (Exception e) {
e.printStackTrace();
}
return proxy;
}
return bean;
}
}
2、ProxyFactoryBean.java
public class ProxyFactoryBean {
private Advice advice;
private Object target;
... get和set方法
public Object getProxy() {
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
/*new Class[]{Collection.class},*/
target.getClass().getInterfaces(),
new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy3;
}
}
3、config.properties
#xxx=java.util.ArrayList
xxx=cn.itcast.day3.aopframework.ProxyFactoryBean
xxx.advice=cn.itcast.day3.MyAdvice
xxx.target=java.util.ArrayList
4、测试类:
public class AopFrameworkTest {
public static void main(String[] args) throws Exception {
InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
Object bean = new BeanFactory(ips).getBean("xxx");
System.out.println(bean.getClass().getName());
((Collection)bean).clear();
}
}
-
作用:返回字节码对象。如果字节码之前被加载过,已存在JVM中,则直接返回...;如果没有,则先用类加载器加载,将加载的字节码保存到JVM中,然后返回... ↩