day07
1、上节内容回顾
2、java基础加强
myeclipse安装和使用
** 区分eclipse和myeclipse区别
1、eclipse是一个免费的开源的开发工具
2、myeclipse是一个收费的插件(破解版本)** 如果创建项目
** 打开myeclipse时候,会创建一个工作空间: 工作空间的路径不能带中文 比如: F:\itcast\20150302** 点击file-new-选择项目类型:比如Java Project ** 会有一个jdk环境,可以使用开发工具自带的jdk环境,也有可以使用自己本地安装的jdk - 如何使用本地安装的jdk环境:
** 项目名、类名、方法名、变量的命名方式
- 包的名称方式:使用小写字母 比如 cn.itcast.test01
- 项目命名:使用小写字母名称 比如 day07
- 类命名:使用第一个字母要大写 如果有多个单词,每个单词的首字母大写 比如:TestUserName
- 方法命名: 方法名的首字母小写 如果有多个单词,从第二个单词开始首字母要大写 比如:userManager()
- 变量命名:变量名的首字母小写,如果有多个单词,从第二个单词开始首字母要大写 比如: String userName = “zhangsan”;** 最基本原则:见名知意(看到这个名字能够看懂什么含义) *** 一定不要这样命名: yonghuManger 汉语拼音不要简写: rlgl
** 项目的运行方式:
* run as – java application
* dubug as – java applicationdebug调试模式(断点模式)
** 调试程序
1、设置一个断点 双击 这个时候程序运行到这一行时候,停止。
2、向下执行(单步执行) step over (F6)
3、resume F8:跳出当前的断点(如果后面有断点,会到这个断点,如果没有会结束程序)** 查看源代码
1、step into F5: 进入到源代码里面
2、drop to frame:回到方法的顶端
3、step return F7: 从方法中跳出** 去掉断点的方法
1、skip all breakPoints
2、remove all breakpointsmyeclipse快捷键
- 看文档
junit单元测试
单元测试:测试一个类,一个方法
引入junit支持的jar包,myeclipse中已经自带了这个jar包
入门
@Test
public void testSwim() {
TestJunit test1 = new TestJunit();
int a = 10/0;
test1.swim();
}
1、创建一个源代码文件夹 test
2、在这个test文件夹下 创建一个和要测试的类相同的包
3、使用注解方式 @Test来进行测试
* 测试方法的规范:必须是 public void 方法名() 现在使用junit4.x*** 在junit3.x 时候命名 : public void 方法名() 方法名必须是 testXX开头
4、运行测试方法:
*run as - junit test
* 如果出现绿色的条,表示测试方法通过
* 直接在类中点击 run as - junit test 把所有可以运行的方法执行- @Test:这个方法可以进行单元测试
@Ignore:表示当前方法不做单元测试(不运行)
@After: 在方法之后 执行
- @Before:在方法之前执行
- @BeforeClass:在类加载之前执行 static方法 只会执行一次
- @AfterClass:在类加载之后执行 static方法 只会执行一次
jdk5.0的一些新特性
jdk发展 1.1 1.2 1.4 jdk5.01、泛型(****)
* 泛型经常使用在集合上 ,
* 如果集合没有使用泛型,向集合里面添加数据之后,数据失去了原有的类型,如果想要取数据,这个时候很容易出现
类型转换问题。
* 如果使用了泛型,可以定义这个集合里面的数据的类型,可以避免类型转换的问题* 常用集合 List Set Map ** 在List上使用泛型 * List<String> list = new ArrayList<String>(); * list遍历方式有三种:普通for,增强for,迭代器 ** 在set上使用泛型 * Set<String> set = new HashSet<String>(); * set遍历方式有两种:增强for,迭代器 * set和list区别(***) ** map上使用泛型 * Map<String,String> map = new HashMap<String,String>(); * map遍历方式,两种: ** 一种是获取所有key 根据key获取value - //先获取所有的key Set<String> set = map.keySet(); //遍历set for (String key : set) { //根据key获取value String value = map.get(key); System.out.println("key: "+key+" value:"+value); } ** 第二种是获取key-value的关系 - //获取key - value关系 Set<Entry<String,String>> set1 = map.entrySet(); //遍历set1 for (Entry<String, String> entry : set1) { String key = entry.getKey(); String value = entry.getValue(); System.out.println("key: "+key+" value:"+value); } * 泛形的基本术语,以ArrayList<E>为例:<>念着typeof ArrayList<E>中的E称为类型参数变量 ArrayList<Integer>中的Integer称为实际类型参数 整个ArrayList<Integer>称为参数化类型ParameterizedType * 泛型里面的类型只能是对象 对应八种基本数据类型的包装类和String * 在方法上使用泛型 - 实现指定位置上数组元素的交换 - 实现逻辑相同,只是数据类型不同,这个时候使用泛型方法 - 定义方式: /* * 使用<T> <A> <B> :表示任意的类型 * 写在返回值之前 * 当在方法上定义了这个类型之后,这个类型就可以在方法中使用 * */ public static <T> void swap1(T[] arr,int i,int j) { T temp = arr[i]; //temp == 20 arr[i] = arr[j]; // arr[i] == 40 arr[j] = temp; // arr[j] == 20 } * 作业 : 使用泛型方法实现: 任意类型的数组,颠倒数组中所有元素 比如: * Integer[] arr = {10,20}; result: 20,10 * String[] arr1 = {"aa","bb"}; result: "bb","aa" * 在类上使用泛型 - public class TestDemo3<A> { A aa; public void test(A bb) { } public static <B> void test1(B cc) { }} - 在类上定义泛型,在类中都可以使用 *** 在静态方法中不能使用类上定义的泛型
2、枚举(了解)
** 在一定范围内取值,只能出现其中的一个 ,比如交通信号灯 有三种颜色 每次只亮其中的一个。
* 实现的发展历史:
* enum Color3 {
RED,GREEN,YELLOW;
}* 构造方法有参数 在每个实例上加上参数 * 有抽象方法:在每个实例上实现抽象方法 *** 构造方法是私有的 * name() :返回枚举的名称 * ordinal() :枚举的下标 * valueOf(Class<T> enumType, String name):返回一个枚举对象 ** 在类中没有,编译时候生成这两个方法 * valueof(String name) 转换枚举对象 * values() 获得所有枚举对象数组 ** 对象、名称、下标这三个直接的互相转换
3、静态导入(鸡肋)
* 可以在类中导入一些静态的方法
* 导入方式 import static 包名.类名.静态属性|静态方法|
** import static java.util.Arrays.sort;
* 如果import static java.util.Arrays.toString时候,会出错,因为object里面也有toString** 试用的场景: - 比如实现一个计算器,计算器里面的方法都是Math里面的方法,这个时候可以使用静态导入
4、自动装箱/拆箱(**)
* 装箱:把基本的数据类型封装成对象 (包装类)
* 拆箱:把包装类转换成基本数据类型* Integer i = 1; //自动装箱 int m = i; //自动拆箱 * 在jdk1.4实现基本数据类型和包装类的转换 - Integer i = new Integer(1); //实现把基本数据类型转换成包装类 int m = i.intValue(); //实现把包装类转换成基本数据类型 * 常见的笔试题(向下兼容问题) - //在jdk5.0之前会执行doSomething(double i)这个方法,如果到了1.6,还会执行这个方法doSomething(double i) public static void doSomething(double i) { System.out.println("double....."); } public static void doSomething(Integer i) { System.out.println("Integer....."); }
5、增强for循环(****)
* List set :可以使用增强for循环
map:不可以使用增强for循环* 格式 for(数据类型 变量名称 : 要遍历的内容) {} ** 设计增强for循环的目的:为了取代迭代器 ** 增强for循环的底层就是使用迭代器实现的 * 使用增强for循环的规则:必须实现Iterable接口的集合才可以使用增强for循环 - List set之所以可以使用增强for循环,实现了Iterable接口 - map没有实现Iterable接口,所有不能使用增强for循环
6、可变参数(*)
* 比如现在要实现两个数的相加,还要实现三个数的相加,这个时候变化只是参数的个数,这个时候可以可变参数
* 可以直接定义一个方法,实现这些操作* 格式 数据类型...名称 比如 int...nums * public static void add1(int...nums) { //nums是一个数组,有传递过来的所有参数 //System.out.println(nums.length); int sum = 0; //通过nums数组可以实现多个数的相加 for(int i=0;i<nums.length;i++) { sum += nums[i]; } System.out.println(sum); } * 定义规则: 1、一个方法里面只能有一个可变参数 - public static void add1(int...nums1,int...nums):这样是不可以的 2、可变参数必须放在方法的参数列表的最后 - public static void add1(int m,int...nums) 3、可变参数只能放在方法的参数列表中,不能单独定义变量
7、补充内容
* 泛型的擦除:定义这个泛型只是显示在源代码阶段,如果编译成class文件之后,泛型消失。
* 设计的目的:在程序的入口的时候,就规定一个类型* 实现泛型方法,把数组中的元素颠倒 - //定义一个泛型方法 public static <T> void reverse1(T[] arr) { for(int i=0;i<arr.length/2;i++) { T temp = arr[i]; arr[i] = arr[arr.length-i-1]; arr[arr.length-i-1] = temp; } }
7、反射(*****重点理解)
* 框架 底层都是使用反射来实现的。
* 一些通用性比较高的代码
* 画图分析原理
** 1、类要保存到本地硬盘 Person.java
2、编译成class文件 Person.class
3、使用类加载器把class文件加载到内存中,使用jvm操作4、class文件在内存中的内容使用 Class类 进行表示 5、可以使用反射来获取类中的所有内容 - 属性,方法,构造(有参数和无参数的)(私有的属性和方法) 6、获取到Class类,有三种方式: - 类名.class - 对象.getClass() - Class.forName("cn.itcast.servlet.TestServletDemo1"); * 属性使用 Field类表示 构造方法使用 Constructor类表示 方法使用 Method类表示 * Class类的api查看 - forName(String className) :参数是包类名称 - getConstructors() :返回所有的构造方法 返回 是一个 Constructor[]数组 - getConstructor(Class<?>... parameterTypes) :根据具体的参数返回相应的方法 - getDeclaredFields() :返回所有的属性 Field[]数组 - getDeclaredField(String name) :参数是属性名称 返回 Field - getMethods() :返回所有的方法 返回数组 Method[] - getMethod(String name, Class<?>... parameterTypes) :返回单一的方法 * 想要获取 setName(String name) * getMethod("setName",String.class) * 获取Class类 * //类名.class // Class class1 = Person.class; // //使用对象获取 // Class class2 = new Person().getClass(); // //使用forname方法/day07/src/cn/itcast/test11/Person.java // Class class3 = Class.forName("cn.itcast.test11.Person"); * 操作构造方法 - 无参数的构造方法: Person p3 = (Person) class3.newInstance(); - 有参数的构造方法: 1、获取到有参数的构造方法 - Constructor constructor = class3.getConstructor(String.class,String.class); 2、获取实例 - Person p1 = (Person) constructor.newInstance("lisi","100"); * 操作属性 1、获取到要操作的属性 - Field field = class3.getDeclaredField("name"); 2、设置属性的值 - field.set(实例对象, "wangwu"); ***** 如何想要获取私有属性的时候 field.setAccessible(true); 3、获取值 - field.get(p3) * 操作方法 1、获取到要操作的方法 - Method method = class3.getMethod("setName", String.class); 2、想要某个方法执行 - method.invoke(p3, "zhaoliu"); ***** 想要访问私有的方法 method.setAccessible(true); ** 静态方法: method.invoke(null, "zhaoliu");
package map;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import bean.Student;
/**
* map使用
* @author Administrator
* map的使用场景:存放的是键与值的映射 键 是唯一 值可以重复
* map缓存数据
* 1. 调用 Map 的 get() 方法获取数据;
如果返回不为 null, 直接返回该数据;
如果返回为 null, 则生成数据, 或者从其他地方获取数据, 然后存放入 Map 中, 最后返回该数据.
这里, 我们可以通过使用 Map 的containsKey() 方法来检测是否数据是否存在, 如果key存在, 则表明已经获取过一次数据, 那么直接返回该 key 在 Map 中的值. 不管是否为 null 都直接返回; 如果 key 不存在, 则去生成或者获取数据, 并放入到 Map 中, 并返回该数据.
这里使用 containsKey() 来检测可以应用于: 1. 从其他对方获取的数据可能为空, 并且不会有变化; 2. 获取数据比较耗时. 这个场景下, 使用该方法可以大大降低消耗, 特别是在同步情况下.
*/
public class Map01 {
public static void main(String[] args) {
Map<String,String> map=new HashMap<String,String>();
map.put("name", "q1");
map.put("age", "q2");
map.put("school", "q3");
//if(!map.containsKey("01")){
//}else{
// System.out.println("当前已经存在");
//}
Student stu=new Student();
mapToBean(map,stu.getClass());
Student stu2=new Student();
stu2.setName("zhangsan");
stu2.setAge("18");
stu2.setSchool("bayixiaoxue");
Map<String,Object> map2 =beanToMap(stu2);
//遍历的方式
//1 Set 遍历方式
Set<String> keySet = map2.keySet();
for (String s : keySet) {
System.out.println(s+":"+map2.get(s));
}
//2Entry 遍历方式
Set<Entry<String, String>> entrySet = map.entrySet();
for (Entry<String, String> entry : entrySet) {
//System.out.println(entry.getKey()+":"+entry.getValue());
}
}
/**
* bean 转换为map 反射
* @param value
* @return
*/
public static Map<String, Object> beanToMap(Object value) {
//if (value instanceof Map<?, ?>) {
// return _resetMap(value);
//}
Map<String, Object> map = new HashMap<String, Object>();
if (value == null) {
return map;
}
Class<?> cls = value.getClass();
for (Field field : cls.getDeclaredFields()) {
try {
field.setAccessible(true);
map.put(field.getName(), field.get(value));
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
// 获取父类属性
Class<?> supcls = cls.getSuperclass();
for (Field field : supcls.ggetetDeclaredFields()) {
try {
field.setAccessible(true);
map.put(field.getName(), field.get(value));
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return map;
}
/**
* map集合转bean 实体
* @param map
* @param type
*/
private static void mapToBean(Map<String, String> map,Class type) {
try {
//获取beaninfo 对象
BeanInfo beanInfo = Introspector.getBeanInfo(type);
//bean实体对象的属性数组
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
Object obj=type.newInstance();
for (int i = 0; i < propertyDescriptors.length; i++) {
PropertyDescriptor propertyDescriptor=propertyDescriptors[i];
//属性名称
String name = propertyDescriptor.getName();
if(map.containsKey(name)){
//给该对象对应的属性赋值
propertyDescriptor.getWriteMethod().invoke(obj, map.get(name));
}
}
Student s=(Student)obj;
System.out.println(s);
} catch (IntrospectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 获取类属性
catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Hashtable
extends Dictionary
implements Map, Cloneable, java.io.Serializable
[java] view plaincopy
public class HashMap
extends AbstractMap
implements Map, Cloneable, Serializable
可见Hashtable 继承自 Dictiionary 而 HashMap继承自AbstractMap
Hashtable的put方法如下
[java] view plaincopy
public synchronized V put(K key, V value) { //###### 注意这里1
// Make sure the value is not null
if (value == null) { //###### 注意这里 2
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash = key.hashCode(); //###### 注意这里 3
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index]; e != null; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
modCount++;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
Entry e = tab[index];
tab[index] = new Entry(hash, key, value, e);
count++;
return null;
}
注意1 方法是同步的
注意2 方法不允许value==null
注意3 方法调用了key的hashCode方法,如果key==null,会抛出空指针异常 HashMap的put方法如下
[java] view plaincopy
public V put(K key, V value) { //###### 注意这里 1
if (key == null) //###### 注意这里 2
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i); //###### 注意这里
return null;
}
注意1 方法是非同步的
注意2 方法允许key==null
注意3 方法并没有对value进行任何调用,所以允许为null
补充:
Hashtable 有一个 contains方法,容易引起误会,所以在HashMap里面已经去掉了
当然,2个类都用containsKey和containsValue方法。
HashMap Hashtable
父类 AbstractMap Dictiionary
是否同步 否 是
k,v可否null 是 否
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,
主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。
HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步(Collections.synchronizedMap)。
Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。
来源: http://blog.csdn.net/shohokuf/article/details/3932967
public class Hashtable
extends Dictionary
implements Map, Cloneable, java.io.Serializable
[java] view plaincopy
public class HashMap
extends AbstractMap
implements Map, Cloneable, Serializable
可见Hashtable 继承自 Dictiionary 而 HashMap继承自AbstractMap
Hashtable的put方法如下
[java] view plaincopy
public synchronized V put(K key, V value) { //###### 注意这里1
// Make sure the value is not null
if (value == null) { //###### 注意这里 2
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash = key.hashCode(); //###### 注意这里 3
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry e = tab[index]; e != null; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
modCount++;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
Entry e = tab[index];
tab[index] = new Entry(hash, key, value, e);
count++;
return null;
}
注意1 方法是同步的
注意2 方法不允许value==null
注意3 方法调用了key的hashCode方法,如果key==null,会抛出空指针异常 HashMap的put方法如下
[java] view plaincopy
public V put(K key, V value) { //###### 注意这里 1
if (key == null) //###### 注意这里 2
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i); //###### 注意这里
return null;
}
注意1 方法是非同步的
注意2 方法允许key==null
注意3 方法并没有对value进行任何调用,所以允许为null
补充:
Hashtable 有一个 contains方法,容易引起误会,所以在HashMap里面已经去掉了
当然,2个类都用containsKey和containsValue方法。
HashMap Hashtable
父类 AbstractMap Dictiionary
是否同步 否 是
k,v可否null 是 否
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,
主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上可能高于Hashtable。
HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步(Collections.synchronizedMap)。
Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。