Java基础加强_Eclipse、枚举、反射、注解、泛型、类加载器、动态代理

本文详细介绍了Eclipse开发工具的使用,包括工作间管理、快捷键设置、视图管理与调试,以及Java5的新特性如枚举、反射、注解和泛型的应用。此外,还探讨了类加载器、动态代理技术以及AOP概念,展示了如何利用反射和注解实现框架开发。通过对这些内容的深入学习,读者可以提升Java开发技能,理解Java核心技术的运用。
摘要由CSDN通过智能技术生成

第1单元:Eclipse开发工具

eclipse及IDE开发工具介绍

MyEclipse是eclipse的一个插件,使得eclipse可以开发JavaEE项目

javaw.exe是启动java的图形界面所用的虚拟机

Java EE: Java Enterprise Edition

IDE: Integrated Development Environment

WorkSpace:工作间

工程管理与快捷键设置

一个工作间workspace的设置应用于它包含的所有project

设置整个工作间编译器版本和运行时环境的版本

window-->Preferences-->Java-->compiler或者installed JREs

切换workspace:File-->Switch Workspace,自命名一个workspace,没有则自动创建并打开一个工作间

perspective:透视图

每个java文件都要有一个包名,包名是公司的网址倒着写(去哪个公司面试包名就写哪个公司)

想要更改工程名,右键工程名选重构refactor-->rename。如果别的地方调用了这个类,类名也会跟着改,这就是重构的好处

为当前工作间下所有的工程设置快捷键

window-->preferences-->general-->Keys,输入content assist,选择unbind command解除原绑定,然后再设置新的快捷键,注意不要和其他快捷键冲突

查看工程所在目录:安装OperExplorer插件,点击Open Explorer图标即可

eclipse快捷键

提示快捷键:比如设置content assist:alt + / ,输入syso再按该快捷键就可以输出打印语句。注意:一般自动补全快捷键:word completion的快捷键默认也是alt+/,所以此时需要对其进行修改

Ctrl+z/y:取消/还原上次操作

Alt+↓: 移动当前行

Ctrl+Alt+↓: 复制当前行到下一行(复制增加) 

Ctrl+Alt+↑ :复制当前行到上一行(复制增加)

Ctrl+I :正确缩进代码

Ctrl+/ :单行注释

Ctrl+Shift+/ :多行注释

Ctrl+T:查看类或者接口的实现类

Alt+Shift+r :选中所有同一变量,方便进行批量修改

Alt+Shift+S/右键选Source-->Generate Constructor using Fields:Eclipse自动根据定义好的字段生成构造函数

直接复制源代码在某包下,自动生成相应文件!

视图管理与程序调试

一个透视图perspective就是若干个小窗口view的集合

如果关闭了一个view就点window-->show view来打开

调试一个变量debug步骤

  1. 在需要debug的代码前双击产生端点
  2. 点右键单击debug as进如debug透视图
  3. 鼠标选中一个变量,右键选watch就可以看到它的值
  4. 选择step over先前走一步观察变量的变化

配置eclipse的编译与运行环境

如何设置单个工程的Javac和Java?
选择工程右键选properties-->compiler设置javac
右键选择run as 中的configurations来设置java运行环境
高版本的JRE能否运行低版本的javac编译的程序?可以
低版本的JRE能否运行高版本的javac编译的程序?不可以,会出现bad version number in .class file错误

在eclipse中配置java模板代码

选取一段代码,右键选择surround with 选取需要生成的模板代码
自己配置需要的模板:
preferences-->java-->Editor下拉-->templates中new一个自定义模板,需要在模板中定义cursor和line_selection

在eclipse中导入已有的工程

首先,将工程文件拷贝至workspace目录下
然后,File-->Import-->Genereal-->Existing Projects into Workspace/File System选择该工程的根目录确认即可
如果导入工程的JRE和自己eclipse的JRE不一样(比如JRE的安装目录以及JRE所含的jar包不一样),右键工程名-->build path-->configure build path-->libraries下把该工程原JRE库删除,再增加自己的JRE库
add jars:增加单独的jar包(当jar包存在于工程内但未导入)
add external jars:要导入不在工程内的jar包
add library:增加一个库,该库中有许多jar包
可以自定义一个库,选择User Library,命名一个新的库,然后再在库里增加jar包

第2单元:java5的一些简单新特性

java5的静态导入与编译器语法设置

import可以导入某个类或者某个包中的所有类
import static导入一个类中的某个 静态方法或者所有静态方法
import static java.lang.Math.max;//注意不要写掉static
...
System.out.println(max(3,6));//省略调用类名

如果编译器的jdk版本低于1.5会报错!

Java5的可变参数与OverLoad与Override相关面试题

一个方法接受的参数个数不固定时,就使用可变参数
可变参数VariableParameter的特点:
  • 只能出现在参数列表的最后
  • 三个点...位于变量类型和变量名中间,前后有无空格都可以
  • 调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,该方法体中以数组的形式访问可变参数
public static int add(int x,int... args){
	int sum = x;
      /*for(int i=0;i<args.length;i++){
		sum += args[i];
	}*/
	//for循环增强
	for(int arg : args){
		sum += arg;
	}
	return sum;
}

面试题:overload vs override
两个方法的参数列表完全一样但是返回值不一样,不是overload,overload只看同名函数的参数列表,参数列表不同的函数才能实现重载
父类方法私有,子类的一个方法与之一模一样,不是override

Java5的增强for循环

语法:for(变量类型   变量名 : 集合变量名) { ... } 
使用见上面代码
学会阅读java的语言规范langspec-3.0

Java5的基本数据自动拆装箱及享元设计模式

自动装箱:Integer num1 = 12;
自动拆箱:num1+12;

Integer num1 = 13;
Integer num2 = 13;
num1和num2为同一个对象

Integer num1 = 137;
Integer num2 = 137;
num1和num2不是同一对象,与字符串一样

手动包装同自动装箱一样!
Integer num3 = Integer.valueOf(213)

原因: 为了节省内存空间,因为小的数使用频率高,大数适用频率低,所以对于-128~127之间的数字,一旦被包装成一个Integer对象之后就会被缓存起来,当下一个又被装成Integer对象时,先看缓存池中有木有,有就直接拿来用。

以上的设计是一种设计模式: 享元模式 flyweight
当一个对象经常使用,大量重复,就将其设计成享元模式,把相同的属性用对象包装,称为内部状态,不同的变成外部属性,作为方法的参数传入,比如字母i,字符char为相同属性,位置为不同的变量,i.display(x,y)

第3单元:Java5的枚举

枚举的作用

枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。
枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。

用普通类模拟枚举的实现原理

定义一个WeekDay的类来模拟枚举功能:
  • 私有的构造方法
  • 每个元素分别用一个公有的静态成员变量来表示
  • 可以有若干公有方法或者抽象方法,例如要提供nextDay()方法必须是抽象的
public abstract class WeekDay1 {
	private 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;
		}
		
	};	
	
	public abstract WeekDay1 nextDay(); //采用抽象方法定义nextDay就将大量的if else语句转移成了一个个独立的类,这里在对象实例化时用匿名内部类来定义子类对象,public可以让子类实现该方法
	
/*	public WeekDay nextDay(){
		if(this == SUN){
			return  MON;
		}else{
			return SUN;
		}
	}
*/
	
	public String toString(){
		return this==SUN?"SUN":"MON";
	}
}

枚举的基本应用

枚举是一种特殊的类,不用关键字class标识,而是通过关键字 enum来标识一个枚举类,每一个枚举元素都是该类的一个实例对象,例如可以调用WeekDay.SUN.getClass().getName()和WeekDay.class.getName();

枚举类的方法

非静态方法:name,toString,ordinal

静态方法:values,valueOf

		public static void main(String[] args) {
			WeekDay weekDay2 = WeekDay.FRI;//访问枚举类中的元素
			System.out.println(weekDay2);
			System.out.println(weekDay2.name());//结果为FRI
			System.out.println(weekDay2.ordinal());	//返回weekDay2的排序,此例为5,ordinal意思是序数
			System.out.println(WeekDay.valueOf("SUN").toString());//将SUN字符串包装成一个WeekDay类型的枚举对象,等同于WeekDay.SUN
			System.out.println(WeekDay.values().length); //values返回一个枚举类型数组
		}

可以将枚举定义为内部类,此时:public enum WeekDay{SUN,MON,TUE,WED,THI,FRI,SAT//此后无语句,不需要加分号}}

 

 
 

实现带有构造方法的枚举

元素列表必须放在所有语句之前,包括构造方法,此时元素列表最后要有分号
        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 static void main(String[] args) {
		WeekDay day2 = WeekDay.TUE;
	}
运行结果


实现带有抽象方法的枚举

外部类可以有两个修饰符,一个默认的,一个public
内部类可以有四个访问修饰符
实现一个交通灯的枚举类(最复杂的枚举)
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();//在父类中定义一个nextLamp的抽象方法,通过上面的匿名内部类来定义该方法的实现,public让子类可以实现该方法
	private int time; //每种灯都有一个时间
	private TrafficLamp(int time){this.time = time;}//时间通过构造方法传入,构造方法为private,代表只能在本类中使用
}
说明:new Date(300){};  该写法是允许的,表示子类的构造方法内部会调用父类的构造方法,并且调用的是父类的有参的构造方法,而不需要在子类中写明该调用,参见上面交通灯例子
枚举只有一个元素时,可以作为单例设计模式的一种实现

第4单元:Java1.2的反射

反射的基础_Class类

Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class
要注意与小写的java关键字区别
Class类描述的类的名字,类的访问属性,类所属的包名,字段名称的列表,方法名称的列表等等
Class类不能直接new对象,因为没有构造方法,它的各个实例对象分别对应各个类在内存中的字节码,例如Person类的字节码,ArrayList类的字节码等等
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码

如何得到各个字节码对应的实例对象

  1. 类名.class,例如,Class cls1 = Date.class;
  2. 对象.getClass(),例如,new Date().getClass();
  3. Class.forName(完整的包名+类名),例如,Class.forName("java.lang.String"); 做反射时主要使用该方法,因为在写源程序的时候还不知道类名,需要作为参数传递。该方法会抛出异常ClassNotFoundException
面试题:forName的作用是返回字节码,返回的方式有两种:1,字节码已经被JVM加载过,直接返回。2,JVM里还没有该字节码,则用类加载器加载,把加载进来的字节码缓存在虚拟机里面,再返回

九个预定义Class实例对象

8个基本数据类型+1个void关键字
参看Class的isPrimitive()方法的帮助
类名.isPrimitive()判断该类是否为原始类型
int.class == Integer.TYPE的结果为true,因为TYPE字段代表被包装的基本数据类型的字节码
数组类型的class实例对象判断使用的是Class 的isArray()
                String str1 = "abc";
		Class cls1 = str1.getClass();
		Class cls2 = String.class;
		Class cls3 = Class.forName("java.lang.String");
		System.out.println(cls1 == cls2);//true,内存中只会有一份字节码文件
		System.out.println(cls1 == cls3);//true
		
		System.out.println(cls1.isPrimitive());//fasle
		System.out.println(int.class.isPrimitive());//true
		System.out.println(int.class == Integer.class);//false
		System.out.println(int.class == Integer.TYPE);//true,TYPE字段代表被包装的基本数据类型的字节码
		System.out.println(int[].class.isPrimitive()); //false
		System.out.println(int[].class.isArray());//true
总之,只要是在源程序中出现的类型,都有各自的class实例对象,例如int[],void

理解反射的概念

反射就是将java类中的各种成分映射成相应的java类
例如,一个java类用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的java类来表示。
表示java类的Class类显然要提供一系列的方法来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应的类的实例对象来表示,它们是Field,Method,Constructor,Package等等
一个类中每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class实例对象的方法可以得到这些实例对象并加以应用。

构造方法的反射

Constructor类的对象代表某个类中的一个构造方法

得到某个类所有的构造方法

Constructor [ ] constructors = Class.forName("java.lang.String").getConstructors();

得到某一个构造方法

Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);//传入的是Class对象,通过参数列表来确定要得到那个构造方法,注意获得构造方法时要用到的类型

创建实例对象

一般方式:new String(new StringBuffer("abc")); 
反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));//因为编译时编译器不知道该构造方法对象constructor是属于哪个类的,只有运行时程序才知道,所以写程序时要加上类型强转(String)告诉编译器,注意调用创建实例对象的newInstance方法时要用到上面相同类型的实例对象

Class的newInstance()方法

例子:String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的不带参数的构造方法,然后用该构造方法创建实例对象。省略了获取构造方法的步骤
该方法内部的具体代码是怎样写得呢?用到了缓存机制来保存默认构造方法的实例对象,所以反射会导致程序性能下降

成员变量的反射

Field类的对象代表某个类中的一个成员变量
Eclipse自动生成构造函数源代码:定义好字段,Alt+Shift+S/右键选Source-->Generate Constructor using Fields
public class ReflectPoint {
	public int y;
	private int x;
	int z;
	public ReflectPoint(int x, int y,int z) {
		super();
		this.x = x;
		this.y = y;
		this.z = z;
	}
}

通过反射进行操作:

        ReflectPoint pt1 = new ReflectPoint(3,5,2);
	//被public修饰的变量,通过getField方法获取
	Field fieldY = pt1.getClass().getField("y");//fieldY的值是多少?是5,错!fieldY不是对象身上的变量的值,而是类上定义的变量"y",要用它去取某个对象上对应的值
	//在pt1对象身上拿到对应的变量的值,结果为3
	System.out.println(fieldY.get(pt1));
	//对于只要是在类中声明过的成员变量(包括public),都可以通过getDeclaredField方法获取
	//被private修饰的变量,只能通过getDeclaredField方法获取(让该字段可见,但是还不能获取该字段的值)
	Field fieldX = pt1.getClass().getDeclaredField("x");
	//然后通过setAccessible将该变量的值设置为可以访问,也叫暴力反射(让该字段的值可以拿到)
	fieldX.setAccessible(true);
	//打印结果为5
	System.out.println(fieldX.get(pt1));
	//无访问修饰符的变量,只能通过getDeclaredField方法获取
	Field fieldZ = rp.getClass().getDeclaredField("z");
	//此时该变量的值即可访问,结果为2
	System.out.println(fieldZ.get(rp));

 
 

成员变量反射的综合案例

将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改成“a”
        private static void changeStringValue(Object obj) throws Exception {
		Field[] fields = obj.getClass().getDeclaredFields();
		for(Field field : fields){
			//if(field.getType().equals(String.class)){
			if(field.getType() == String.class){ //字节码,也就是Class类的对象,用等号比较地址值,因为内存中都只有一份
				String oldValue = (String)field.get(obj);
				String newValue = oldValue.replace('b', 'a');
				field.set(obj, newValue);//最后还要给对象中的成员变量赋值
			}
		}
		
	}

成员方法的反射

Method类的对象代表某个类中的一个成员方法

得到类中的某一个方法

Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class); //int.class表示的是参数类型,通过此列表来明确多个重载方法中的一个

调用方法

  • 通常方式:str.charAt(1);
  • 反射方式:charAt.invoke(str,1); //str为调用该方法的对象,1为传入该方法的参数,invoke方法参考画圆的方法circle.draw(),画圆的参数是圆的私有属性,所以画圆的方法是属于圆的(专家模式)
如果传递给Method对象的invoke方法的第一个参数为null,说明该Method对象对应的是一个静态的方法

jdk1.4和jdk1.5的invoke方法的区别

  • jdk1.5: public Object invoke(Object
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值