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

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>为例:<>念着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() 方法获取数据;

  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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值