一、Eclipse的使用

1、在eclipse下Java程序的编写和run as,debug as,及java运行环境的配置.
2、快捷键的配置,常用快捷键:
•内容提示:Alt + /
•快速修复:Ctrl + 1
•导包:Ctrl + shift + O
•格式化代码块:ctrl + shift + F
•向前向后:Alt + 方向键
•添加注释 Ctrl+Shift+/
•除去注释 Ctrl+Shift+\
3、程序的调试和运行
•F5(跳入)、F6(跳过) 、F7(跳出) 、drop to frame(回撤到当前方法起始位置)、resume(跳到下一个断点 ) 、选中变量或表达式后watch可观察当前值.

二、Junit使用

1、@Before、@Test、@After基本使用
public class Demo4 {
@Before
public void before() {
System.out.println("before");
}
@Test
public void testRun() {
Person p = new Person();
p.run();
}
@Test
public void testEat() {
Person p = new Person();
p.eat();
}
@After
public void after() {
System.out.println("after");
}
}

运行结果:

before
eating.
after
before
runing.
after

2、@BeforeClass、@Test、@AfterClass基本使用

public class Demo5 {
@BeforeClass
public void beforeClass() {
System.out.println("beforeclass");
}
@Test
public void testRun() {
Person p = new Person();
p.run();
}
@Test
public void testEat() {
Person p = new Person();
p.eat();
}
@AfterClass
public void afterClass() {
System.out.println("afterclass");
}
}

运行结果:

before
eating.
runing.
after

三、JDK 5.0 新特性

JDK5中新增了很多新的java特性,利用这些新语法可以帮助开发人员编写出更加高效、清晰,安全的代码.

1、静态导入,(了解即可,一般没人这么用)

语法:•Import static 包名.类名.静态属性|静态方法|*
import static java.lang.System.out;
import static java.util.Arrays.sort; public class Demo1 {
public static void main(String[] args) {
out.print("main");
int[] a = new int[] { 6, 5, 3 };
sort(a);
for (int i : a)
out.print(i);
}
}

2、自动装箱/拆箱

•自动装箱:指开发人员可以把一个基本数据类型直接赋给对应的包装类.
•自动拆箱:指开发人员可以把一个包装类对象直接赋给对应的基本数据类型.
public class Demo2 {
public static void main(String[] args) {
Integer i = 1;// 装箱
int j = i;// 拆箱
// 典型应用,list里只能装对象
List<Integer> list = new ArrayList<Integer>();
list.add(1);// 1被自动包装为Integer
int k = list.get(0);// 自动拆箱
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
int m = it.next();// 拆箱
}
}
}

3、增强for循环

•引入增强for循环的原因:在JDK5以前的版本中,遍历数组或集合中的元素,需先获得数组的长度或集合的迭代器,比较麻烦!
•JDK5中定义了一种新的语法——增强for循环,以简化此类操作.增强for循环只能用在数组、或实现Iterable接口的集合类上,如list,set可以,map不行.

Map for增强实例:

package cn.itcast.demo;

import java.util.*;
import java.util.Map.Entry;
import org.junit.Test; public class Demo3 { @Test
public void test3(){
Map map=new HashMap();
map.put("1", "aaa");
map.put("2", "bbb");
map.put("3", "ccc");
//传统方式1
Set set=map.keySet();
Iterator it=set.iterator();
while(it.hasNext()){
String key=(String)it.next();
String value=(String) map.get(key);
System.out.println("key="+key+",value="+value);
}
//传统方式2
Set set2=map.entrySet();
Iterator it2=set2.iterator();
while(it2.hasNext()){
Map.Entry entry=(Entry)it2.next();
System.out.println("key="+entry.getKey()+",value="+entry.getValue());
}
//增强for循环的1种方式,实际转为的set视图只存了key
for(Object obj:map.keySet()){
String key2=(String)obj;
String value2=(String)map.get(key2);
System.out.println("key2="+key2+",value2="+value2);
}
//增强for循环的2种方式
for(Object obj:map.entrySet()){
Map.Entry entry3=(Entry) obj;
String key3=(String) entry3.getKey();
String value3=(String) entry3.getValue();
System.out.println("key3="+key3+",value3="+value3);
}
//增强for循环需要注意的问题:只适合取数据,不适合更改
int arr[]={1,2,3};
for(int i: arr){
i=10;
}
System.out.println(arr[0]); //
List li=new ArrayList();
li.add("1");
for(Object obj : li){
obj="888";
}
System.out.println(li.get(0));//
}
}

4、可变参数

语法:

public void foo(int … args){}//三个点

注意事项:

•调用可变参数的方法时, 编译器将自动创建一个数组保存传递给方法的可变参数,因此,程序员可以在方法体中以数组的形式访问可变参数.
•可变参数只能处于参数列表的最后, 所以一个方法最多只能有一个长度可变的参数.
public class Demo4 {
@Test
public void testSum(){
sum(1,2,3,4);
int arr[]={5,6,7};
sum(arr);
}
public void sum(int ...nums){
int sum=0;
for(int i:nums){
sum+=i;
}
System.out.println(sum);
}
//可变参数注意的问题
//public void aa(int ...nums,int s)//不可以,编译器晕逼了
//public void bb(int s ,int ...nums)//可以
@Test
public void asListTest(){//api: public static <T> List<T> asList(T... a)
List list=Arrays.asList("1","2","3");
System.out.println(list);//[1, 2, 3] String arr[]={"1","2","3","4"};
list=Arrays.asList(arr);
System.out.println(list);//[1, 2, 3, 4] arr是对象数组 int nums[]={1,2,3,4,5};
list=Arrays.asList(nums);
System.out.println(list);//[[I@120d62b],nums是一个对象 Integer nums2[]={1,2,3,4,5};
list=Arrays.asList(nums2);
System.out.println(list);//[1, 2, 3, 4, 5]
}
}

5、枚举类

为什么需要枚举?
•一些方法在运行时,它需要的数据不能是任意的,而必须是一定范围内的值,Java5以后可以直接使用枚举予以解决.新增的 enum 关键字用于定义一个枚举类.
枚举类具有如下特性:
•枚举类也是一种特殊形式的Java类.
•枚举类中声明的每一个枚举值代表枚举类的一个实例对象.
•与java中的普通类一样,在声明枚举类时,也可以声明属性、方法和构造函数,但枚举类的构造函数必须为私有的.
•枚举类也可以实现接口、或继承抽象类.
•JDK5中扩展了swith语句,它除了可以接收int, byte, char, short外,还可以接收一个枚举类型.

定义枚举的狗找函数、方法、字段:

/*
* jdk5之前,只能这么定义
* class Grade{
* private Grade(){ }
* public static final Grade A=new Grade();
* public static final Grade B=new Grade();
* public static final Grade C=new Grade();
* public static final Grade D=new Grade();
* public static final Grade E=new Grade();
* }
*/
enum Grade {
A("100-90"), B("89-80"), C("79-70"), D("69-60"), E("59-0");
private String value;
private Grade(String value){
this.value=value;
}
public String getValue(){
return this.value;
}
} public class Demo1 {
@Test
public void test() {
print(Grade.B);
} public void print(Grade g){ // A B C D E
String value=g.getValue();
System.out.println(value);
}
}

带抽象方法的枚举:

enum Grade {// class A 100-90优 B 89-80良 C 79-70 一般D 69-60差 E 59-0不及格
//必须实现抽象方法
A("100-90"){
public String localeValue(){
return "优";
}
},
B("89-80"){
public String localeValue(){
return "良";
}
},
C("79-70"){
public String localeValue(){
return "一般";
}
}; private String value;
private Grade(String value){
this.value=value;
}
public String getValue(){
return this.value;
}
public abstract String localeValue();
} public class Demo1 {
@Test
public void test() {
print(Grade.B); //89-80,良
} public void print(Grade g){ // A B C D E
String value=g.getValue();
String value2=g.localeValue();
System.out.println(value+","+value2);
}
}

注意:

Java中声明的枚举类,均是java.lang.Enum类的孩子,它继承了Enum类的所有方法.常用方法:

•name() //返回此枚举常量的名称,有毛用
•ordinal() //返回枚举常量的序数
•values() 此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便.

6、反射

1、java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法.简而言之,动态获取类中信息就是反射.

2、java反射应用在很多java软件和框架中,例Tomcat,提供了处理请求和应答的方式,因为具体的处理动作不同,所以对外提供了接口,由开发者来实现具体的请求和应答处理.这个接口就是 servlet,开发者只要实现servlet接口,并配置相应的配置文件,对Tomcat来说就是在web.xml中配置servletname也就是类名,这样tomcat就能通过所谓的反射来加载该类的class文件,并获取类中的所有信息,从而实现开发者自定义的请求和应答处理方式.

3、类用来描述对象共性的信息,用来描述字节码文件的共性的类是Class类,该类提供获取字节码文件中的内容,包括类名称,属性和函数.反射依靠该类来完成.

4、获取字节码文件对象的三种方式:

  1.Object类的getClass()方法,必须实例化类

  2.任何数据类型都具备一个class静态属性(Objcet类的属性)来获取对于的Class对象.

  3.通过给定的类的字符串名称就可以获取该类Class对象,更易扩展,该方法是forName(). 一般使用这种

  例:String name="cn.itcast.Person"; Class c = Class.forName(name);

5、反射构造函数

import java.lang.reflect.Constructor;

class Person{
String name;
int age;
public Person(){
System.out.println("wu can");
}
public Person(String name,int age){
System.out.println("you can");
}
} public class TestPerson {
public static void main(String[] args) throws Exception{
Person p = new Person();
//根据字符串的名称查找该类的字节码文件,加载进内存,创建该字节码文件对象,创建对应的Person对象.
String name="com.czbk.faceObjcet.Person";
Class clazz = Class.forName(name);
//只能调用无参构造函数
Person p1 =(Person)clazz.newInstance();
//调用有参构造函数,getDeclaredConstructor可获取私有构造函数
Constructor c = clazz.getConstructor(String.class,int.class);
Object o=c.newInstance("ww",);
}
}

6、反射字段

public class TestPerson {
public static void main(String[] args) throws Exception{
String str="com.czbk.faceObjcet.Person";
Class clazz = Class.forName(str);
Object o = clazz.newInstance();
Field f = clazz.getField("name"); //只能获取公有属性,可获取父类
Object obj = f.get(o); Field f1 = clazz.getDeclaredField("age");//可获取私有属性,只限本类
f1.setAccessible(true); //对私有字段的访问取消权限检查,暴力访问
System.out.println(f1.get(o));
f1.setInt(o,);
System.out.println(o);
}
}

7、反射方法

public class TestPerson {
public static void main(String[] args) throws Exception{
String str="com.czbk.faceObjcet.Person";
Class clazz = Class.forName(str);
Object o = clazz.newInstance();
//调用无参方法
Method method=clazz.getMethod("toString", null);
method.invoke(o, null);
//调用有参方法
Method method1=clazz.getMethod("toString1", String.class);
method1.invoke(o, "sss");
}
}

8、主板运行实例(接口+配置)

public interface PCI {
void run();
void close();
} public class SoundCard implements PCI{
public void run() {
System.out.println("SoundCard Run");
}
public void close() {
System.out.println("SoundCard Close");
}
} public class NetCard implements PCI{
public void run() {
System.out.println("NetCard run");
}
public void close(){
System.out.println("NettCard clase");
}
} public class MainBoard {
/*public void run(PCI p){
p.run();
}
public void clase(PCI p){
p.close();
}*/
public static void main(String[] args) throws Exception {
//这种方式每次增加新硬件时都需要修改主板源代码
/*SoundCard sc = new SoundCard();
MainBoard mb = new MainBoard();
mb.run(sc);
mb.clase(sc);*/ //增加硬件无需修改MainBoard源代码,只要在配置文件中添加
Properties pt = new Properties();
FileInputStream is = new FileInputStream(new File("PCI.properties"));
pt.load(is); for(int x=0;x<pt.size();x++){
String PCIName=pt.getProperty("pci"+x);
Class clazz = Class.forName(PCIName);
PCI p=(PCI)clazz.newInstance();
Method method = clazz.getMethod("run", null);
method.invoke(p, null);
}
}
}

7、内省(Introspector)

1、为什么要学内省?
•开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,所以sun公司开发了一套API,专门用于操作java对象的属性.
public class Demo1 {
//得到bean所有属性
@Test
public void test1() throws IntrospectionException{
BeanInfo info=Introspector.getBeanInfo(Person.class);
//去掉Object里的属性(也就是class属性)
BeanInfo info2=Introspector.getBeanInfo(Person.class,Object.class);
PropertyDescriptor[] pds=info.getPropertyDescriptors();
for(PropertyDescriptor pd:pds){
System.out.println(pd.getName());
//ab age class name password
}
}
//操纵bean的指定属性:age
@Test
public void test2() throws Exception{
Person p=new Person();
PropertyDescriptor pd=new PropertyDescriptor("age", Person.class);
//得到属性的写方法,为属性赋值
Method method=pd.getWriteMethod();
method.invoke(p, 45);
System.out.println(p.getAge());//45 //获取属性的值
method=pd.getReadMethod();
System.out.println(method.invoke(p, null));//
}
//高级内容,获取当前操作的属性的类型
@Test
public void test3() throws Exception{
Person p=new Person();
PropertyDescriptor pd=new PropertyDescriptor("age", Person.class); //得到属性的写方法,为属性赋值
Method method=pd.getWriteMethod();
System.out.println(pd.getPropertyType());//int
method.invoke(p, 45);
System.out.println(p.getAge());//45 //获取属性的值
method=pd.getReadMethod();
System.out.println(method.invoke(p, null));//
}
}

2、内省—beanutils工具包

Sun公司的内省API过于繁琐,所以Apache组织结合很多实际开发中的应用场景开发了一套简单、易用的API操作Bean的属性——BeanUtils
Beanutils工具包的常用类:•BeanUtils、•PropertyUtils、•ConvertUtils.regsiter(Converter convert, Class clazz)、•自定义转换器
//使用beanUtils操纵bean的属性 ( 第三方)
public class Demo1 {
@Test
public void test1() throws Exception{
Person p=new Person();
BeanUtils.setProperty(p, "age", 456);
System.out.println(p.getAge());//
}
@Test
public void test2() throws Exception{
String name="aaaa";
String age="123";
String password="pw"; Person p=new Person();
//支持8种基本类型自动转换
BeanUtils.setProperty(p, "name", name);
BeanUtils.setProperty(p, "age", age);
BeanUtils.setProperty(p, "password", password); System.out.println(p.getName());//aaaa
System.out.println(p.getAge());//
System.out.println(p.getPassword());//pw }
@Test
public void test3() throws Exception{ String birthday="1983-12-1"; //为了让日期赋值到bean的birthday属性上,给beanUtils注册一个日期转换器
//ConvertUtils.register(converter, clazz);
ConvertUtils.register(new Converter(){ public Object convert(Class type, Object value) {
if(value==null) return null;
if(!(value instanceof String)){
throw new ConversionException("只支持String类型的转换");
}
String str=(String)value;
if(str.trim().equals("")) return null;
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd",Locale.US);
try {
return df.parse(str);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}, Date.class);
Person p=new Person();
BeanUtils.setProperty(p, "birthday", birthday);
System.out.println(p.getBirthday());//pw
System.out.println("___"+BeanUtils.getProperty(p, "birthday"));
}
public void test5() throws Exception {
Map map=new HashMap();
map.put("name", "aaa");
map.put("password", "123");
map.put("brithday", "1980-09-09");
ConvertUtils.register(new DateLocaleConverter(), Date.class);
Person p=new Person();
//用map集合填充bean属性,map关键字和bean属性要一致
BeanUtils.populate(p, map);
}
}

8、泛型(Generic)

1、JDK5以前,对象保存到集合中就会失去其特性,取出时通常要程序员手工进行类型的强制转换,这样不可避免就会引发程序的一些安全性问题,例:

ArrayList list = new ArrayList();
list.add("abc");
Integer num = (Integer) list.get(0); //运行时会出错,但编码时发现不了
JDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出).
2、注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据.但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为"擦除".
•使用泛形时,泛形类型须为引用类型,不能是基本数据类型
ArrayList<String> list = new ArrayList<Object>(); 错,左右必须完全一致
ArrayList<Object> list = new ArrayList<String>(); 错
ArrayList<String> list = new ArrayList (); 对,可以一边没有
ArrayList list = new ArrayList<String>(); 对

3、自定义泛形——泛型方法

Java程序中的普通方法、构造方法和静态方法中都可以使用泛型.方法使用泛形前,必须对泛形进行声明,语法:<T> ,T可以是任意字母,但通常必须要大写.<T>通常需放在方法的返回值声明之前.例如:
public static <T> void doxx(T t);
•编写一个泛形方法,接收一个任意数组,并颠倒数组中的所有元素.
public class Demo1 {
// 编写一个泛形方法,接收一个任意数组,并颠倒数组中的所有元素.
public <T> void reverse(T arr[]) {
int startindex = 0;
int endindex = arr.length - 1;
while (true) {
if (startindex >= endindex)
break;
T temp = arr[startindex];
arr[startindex] = arr[endindex];
arr[endindex] = temp;
startindex++;
endindex--;
} }
}
注意:
•只有对象类型才能作为泛型方法的实际参数.
•在泛型中可以同时有多个类型,例如:
public static <K,V> V getValue(K key) { return map.get(key);}
4、自定义泛形——泛型类和反射泛形
如果一个类多处都要用到同一个泛型,这时可以把泛形定义在类上(即类级别的泛型),语法格式如下:
public class GenericDao<T> {
private T field1;
public void save(T obj) {}
public T getId(int id) {}
}
注意,静态方法不能使用类定义的泛形,而应单独定义泛形.
5、工厂中使用到泛型
//单例
public class ServiceFactory { private Properties serviceConfig = new Properties();
//单例的构造函数也只执行一次
private ServiceFactory(){
InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("service.properties");
try {
serviceConfig.load(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static ServiceFactory instance = new ServiceFactory();
public static ServiceFactory getInstance(){
return instance;
}
public <T> T createService(Class<T> clazz){
//clazz.getName()拿到的带包名
String name = clazz.getSimpleName();
String className = serviceConfig.getProperty(name);
try {
T service = (T) Class.forName(className).newInstance();
return service;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

6、泛型的高级应用——通配符 略

9、Annotation(注解)

1、什么是Annotation,以及注解的作用?三个基本的 Annotation:
•@Override: 限定重写父类方法, 该注解只能用于方法
•@Deprecated: 用于表示某个程序元素(类, 方法等)已过时
•@SuppressWarnings: 抑制编译器警告.
2、Annotation 其实就是代码里的特殊标记, 它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行.在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类.最重要的重要就是直观,替代了配置文件.
3、掌握注解技术的要点:
•如何定义注解
•如何反射注解,并根据反射的注解信息,决定如何去运行类
4、自定义 Annotation
定义新的 Annotation 类型使用 @interface 关键字
声明注解的属性
•注解属性的作用:原来写在配置文件中的信息,可以通过注解的属性进行描述.
•注解属性允许的类型only primitive type, String, Class, annotation, enumeration,一维数组are permitted(集合不允许)
•Annotation 的属性声明方式:String name();
•属性默认值声明方式:String name() default "xxx";
•特殊属性value:如果注解中只有一个名称value的属性,那么使用注解时可以省略value=部分,如@MyAnnotation("xxx")
5、JDK 的元 Annotation
元 Annotation指修饰Annotation的Annotation.JDK中定义了如下元Annotation:
@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留的域, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 通过这个变量指定域.
•RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解. 这是默认值
•RetentionPolicy.RUNTIME:编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注释
•RetentionPolicy.SOURCE: 编译器直接丢弃这种策略的注释
@Target:指定注解用于修饰类的哪个成员. @Target 包含了一个名为 value,类型为ElementType的成员变量.
@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档.
@Inherited: 被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解
@Target(value={ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 { String name() default "zxx";
String password() default "123";
int age() default 12;
Gender gender() default Gender.男;//枚举
MyAnnotation2 my2() default @MyAnnotation2(name="llll");
Class clazz() default String.class;
String[] ss() default {"aa","bbb"};
int[] i() default {1,2};
}

6、提取 Annotation 信息

当一个 Annotation 类型被定义为运行时 Annotation 后, 该注释才是运行时可见, 当 class 文件被载入时保存在 class 文件中的 Annotation 才会被虚拟机读取,具体方法见api.
如下是一个注解可以实现的目的,在一个方法上加个注解,即可自动创建数据源,具体解析过程略.
public class CategoryDao {

    private ComboPooledDataSource combods;

    @Injectpublic void setCombods(ComboPooledDataSource combods) {
this.combods = combods;
}
}
@Retention(RetentionPolicy.RUNTIME)
public @interface Inject {
String driverClass() default "com.mysql.jdbc.Driver";
String jdbcUrl() default "jdbc:mysql://localhost:3306/bookstore";
String user() default "root";
String password() default "root";
}

7、注解在servlet 3.0中的使用案例,替代了在web.xml中的配置:

@WebFilter(
urlPatterns = { "/ServletDemo1" },
initParams = {
@WebInitParam(name = "charset", value = "UTF-8", description = "编码")
})
public class FilterDemo1 implements Filter {
FilterConfig fConfig=null;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
String charset = fConfig.getInitParameter("charset");
HttpServletRequest req = (HttpServletRequest)request;
req.setCharacterEncoding(charset);
chain.doFilter(request, response);
} public void init(FilterConfig fConfig) {
this.fConfig = fConfig;
} public void destroy() {
System.out.println("FilterDemo1 destroy!");
}
}
05-11 17:51