java程序员第七课 java基础加强

来源:互联网 发布:php 去除所有html标签 编辑:程序博客网 时间:2024/05/17 00:07

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 application

  • debug调试模式(断点模式)
    ** 调试程序
    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 breakpoints

  • myeclipse快捷键

    • 看文档
  • 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.0

    1、泛型(****
    * 泛型经常使用在集合上 ,
    * 如果集合没有使用泛型,向集合里面添加数据之后,数据失去了原有的类型,如果想要取数据,这个时候很容易出现
    类型转换问题。
    * 如果使用了泛型,可以定义这个集合里面的数据的类型,可以避免类型转换的问题

    * 常用集合 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>为例:<>念着typeofArrayList<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() 方法获取数据;

  1. 如果返回不为 null, 直接返回该数据;

  2. 如果返回为 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算法都大概一样,所以性能不会有很大的差异。

0 0
原创粉丝点击