java基础复习(集合、泛型、IO流、多线程、Junit 、内省 、Properties、 路径问题)

  • 集合
  • 泛型
  • IO流
  • 多线程
  • Junit
    • Assert
    • 注解
  • 内省
  • Properties
  • 路径问题

集合

---|Collection: 单列集合
    ---|List: 有存储顺序, 可重复
        ---|ArrayList:  数组实现, 查找快, 增删慢
                                由于是数组实现, 在增和删的时候会牵扯到数组
增容, 以及拷贝元素. 所以慢。数组是可以直接按索引查找, 所以查找时较快
        ---|LinkedList: 链表实现, 增删快, 查找慢由于链表实现, 增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记住后一个元素, 后一个元素记住前一个元素. 这样的增删效率较高但查询时需要一个一个的遍历, 所以效率较低
        ---|Vector: 和ArrayList原理相同, 但线程安全, 效率略低
 和ArrayList实现方式相同, 但考虑了线程安全问题, 所以效率略低
    ---|Set: 无存储顺序, 不可重复
        ---|HashSet   线程不安全,存取速度快。底层是以哈希表实现的。
        ---|TreeSet   红-黑树的数据结构,默认对元素进行自然排
                            序(String)。如果在比较的时候两个对象
                            返回值为0,那么元素重复。
---| Map: 键值对   键不可重复,键可以重复
    ---|HashMap    线程不安全,存取速度快。底层是以哈希表实现的.
    ---|TreeMap   红-黑树的数据结构,默认对元素进行自然排
            序(String)。如果在比较的时候两个对象
             返回值为0,那么元素重复
    ---|HashTable  底层也是使用了哈希表 维护的,存取的读取快,存储元素是
                     无序的。

泛型

  1. 泛型类型必须是引用类型
  2. 使用泛型方法前需要进行泛型声明,使用一对尖括号 <泛型>,声明的位置在static后返回值类型前。
  3. 当一个类中有多个函数声明了泛型,那么该泛型的声明可以声明在类上。

函数泛型:

public <T> T getData(T data) {
        return data;
}

类泛型:

public class Demo6<T> {
    public static void main(String[] args) {
        System.out.println(getData2(100));
    }

    public T getData(T data) {
        return data;
    }

    //静态方法不可以使用类中定义的泛型,错误
    public static T getData2(T data) {
        return data;
    }

}
  1. 创建对象的时候要指定泛型的具体类型
  2. 创建对象时可以不指定泛型的具体类型(和创建集合对象一眼)。默认是Object,例如我们使用集合存储元素的时候没有使用泛型就是那么参数的类型就是Object
  3. 类上面声明的泛型只能应用于非静态成员函数,如果静态函数需要使用泛型,那么需要在函数上独立声明(加T)。
  4. 如果建立对象后指定了泛型的具体类型,那么该对象操作方法时,这些方法只能操作一种数据类型。
  5. 所以既可以在类上的泛型声明,也可以在同时在该类的方法中声明泛型。

IO流

读文件:

public static void main(String[] args) {
    String path = "c:/a.txt";
    FileInputStream in = null;
    try {
        // 打开流
        in = new FileInputStream(path);
        // 使用流读文件内容
        int b = in.read();
        while (b != -1) {
            System.out.print((char) b);
            b = in.read();
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        // 释放资源
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

拷贝文件

public static void main(String[] args) {
    String srcPath = "c:/a.txt";
    String destPath = "c:/b.txt";

    // 一定要使用字节流
    InputStream in = null;
    OutputStream out = null;
    try {
        // 打开流
        in = new FileInputStream(srcPath);
        out = new FileOutputStream(destPath);
        // 使用流
        byte[] buf = new byte[1024 * 8];
        for (int len = -1; (len = in.read(buf)) != -1;) {
            out.write(buf, 0, len);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // 释放资源
        try {
            if (in != null) {
                in.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

多线程

两种启动线程方法:

private static int count = 100;

public static void main(String[] args) {
    // 用继承Thread类的方式启动一个线程
    new Thread() {
        public void run() {
            synchronized (StartThreadTest.class) {
                while (count > 0) {
                    count--;
                    System.out.println(Thread.currentThread() + "卖了一张票,还剩" + count);
                }
            }
        }
    }.start();

    // 用实现Runnable接口的方式启动一个线程
    new Thread(new Runnable() {
        public void run() {
            synchronized (StartThreadTest.class) {
                while (count > 0) {
                    count--;
                    System.out.println(Thread.currentThread() + "卖了一张票,还剩" + count);
                }
            }
        }
    }).start();
}

Junit

一、搭建环境:
导入junit.jar包(junit4)

二、写测试类:
0. 一般一个类对应一个测试类。
1. 测试类与被测试类最好是放到同一个包中(可以是不同的源文件夹)
2. 测试类的名字为被测试类的名字加Test后缀。

三:写测试方法:
0. 一般一个方法对应一个单元测试方法。
1. 测试方法的名字为test前缀加被测试方法的名字,如testAddPerson()。
2. 单元测试方法上面要加上@Test注解(org.junit.Test)!
3,单元测试方法不能有参数,也不能有返回值(返回void)!测试的方法不能是静态的方法。

四、测试方法的基本使用:
1. 可以单独执行一个测试方法,也可以一次执行所有的、一个包的、一个类中所有的测试方法。
2. 执行完后,显示绿色表示测试成功;显示红色表示测试失败(抛异常后会测试失败)。

Assert

assertTrue(...)     参数的值应是true
assertFalse(...)    参数的值应是false  

assertNull(...)     应是null值
assertNotNull(...)  应是非null的值

assertSame(...)     使用==比较的结果为true(表示同一个对象)
AssertNotSame(...)  使用==比较的结果为false

assertEquals(...)   两个对象equals()方法比较结果为true

注解:

@Test
    表示单元测试方法。

@Before 
    所修饰的方法应是非static的(且没有参数,返回值为void)。
    表示这个方法会在本类中的每个单元测试方法之前都执行一次。

@After 
    所修饰的方法应是非static的(且没有参数,返回值为void)。
    表示这个方法会在本类中的每个单元测试方法之后都执行一次。


@BeforeClass 
    所修饰的方法应是static的(且没有参数,返回值为void)。
    表示这个方法会在本类中的所有单元测试方法之前执行,只执行一次。

@AfterClass 
    所修饰的方法应是static的(且没有参数,返回值为void)。
    表示这个方法会在本类中的所有单元测试方法之后执行,只执行一次。

内省

开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,所以sun公司开发了一套API,专门用于操作java对象的属性。

内省是用于操作java对象的属性的,那么以下问题我们必须要清楚。

问题一: 什么是Java对象的属性和属性的读写方法?

问题二: 如何通过内省访问到javaBean的属性 ?

1.通过PropertyDescriptor类操作Bean的属性.

public static void testPropertyDescriptor() throws Exception{
        Person p = new Person();
        PropertyDescriptor propertyDescriptor =  new PropertyDescriptor("id",Person.class);
        //获取属性的写的方法。
        Method writeMethod = propertyDescriptor.getWriteMethod();
        Method readMethod = propertyDescriptor.getReadMethod();
        propertyDescriptor.getReadMethod();
        writeMethod.invoke(p, 12);
        System.out.println(readMethod.invoke(p, null));
    }

2.通过Introspector类获得Bean对象的 BeanInfo,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后通过反射机制来调用这些方法。

public static void testIntrospector() throws Exception{
        BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
        PropertyDescriptor[]  descriptor = beanInfo.getPropertyDescriptors();
        for(PropertyDescriptor itemProperty : descriptor){
            System.out.println(itemProperty.getReadMethod().getName());
        }
    }

存在的问题: sun公司的内省API过于繁琐,所以Apache组织结合很多实际开发中的应用场景开发了一套简单、易用的API操作Bean的属性——BeanUtils。

public static void main(String[] args) throws Exception {
        Person p = new Person();
        ConvertUtils.register(new Converter() {

            @Override
            public Object convert(Class type, Object value) {
                 try {
                    if(value!=null){

                         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy MM dd");
                         Date d = dateFormat.parse((String) value);
                         return d;
                     }
                } catch (ParseException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                return null;
            }
        }, Date.class);

        BeanUtils.setProperty(p,"id","110");
        BeanUtils.setProperty(p,"name","狗娃");
        BeanUtils.setProperty(p, "birthDay","1992 12 12");
        System.out.println(p.getId() +"=="+ p.getName()+"======"+p.getBirthDay());
    }

Properties

Properties类对应.properties文件。文件内容是键值对,键值对之间使用”=”或空格隔开。开头是”#”的表示注释

Properties类在加载.properties文件时使用的iso8859-1的编码。所以这个文件中的中文要特殊处理:如果这个配置文件中有中文就必须要进行转义,使用native2ascii.exe命令操作:
native2ascii d:/my.properties d:/my2.properties

使用Properties类中的load(InputStream) 方法可以加载配置文件,使用其中的store(OutputStream) 方法可以保存配置到指定文件。

加载:

public static void testLoadProperties() throws Exception {
    Properties properties = new Properties();

    InputStream in = new FileInputStream("E:/itcast/config.properties");
    properties.load(in); // 加载
    in.close();

    System.out.println(properties);
}

写配置文件:

public static void testStoreProperties() throws Exception {
    // 准备配置信息
    Properties properties = new Properties();
    properties.setProperty("name", "李四");
    properties.setProperty("age", "20");

    // 准备
    OutputStream out = new FileOutputStream("d:/my.properties");
    String comments = "这是我的配置文件";

    // 写出去
    properties.store(out, comments);
    out.close();
}

案例:使用properties读取配置文件,读取数据库的用户名、密码

public class DBUtil {

    static Properties properties = new Properties();

    static{
        try {
            Class clazz = DBUtil.class;
            InputStreamReader fileReader =
            new InputStreamReader(clazz.getResourceAsStream("/db.properties"));
            properties.load(fileReader);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static String getUserName(){
        String userName =properties.getProperty("userName");
        return userName;
    }

    public static String getPassword(){
        return  properties.getProperty("password");
    }
    public static void main(String[] args) {
        System.out.println("用户名:"+ getUserName());
        System.out.println("密码: "+  getPassword());
    }
}

路径问题

绝对路径的问题: 比如C:\abc\a.properties文件路径,该路径在windows上执行没有 问题,但是如果把该项目移动到linux上面执行 ,该路径就会出现问题了,因为在linux上面没有c盘的,只有根目录\。

相对路径存在的问题:相对路径是相对于目前执行class文件的时候,控制台所在的路径,这样子也会导致出现问题。

在Java程序中使用File时写相对路径,是指相对于执行java命令时当前所在的文件夹。

public class PathTest {
    public static void main(String[] args) throws Exception {
        System.out.println(new File("a.txt").getAbsolutePath());
    }
}

获取classpath中的资源(InputStream)

public static void main(String[] args) throws Exception {
    Class clazz = new ClassPathTest().getClass();

    // 开头的'/'表示classpath的根目录,这个是表示从classpath的根目录中开始查找资源
    InputStream in = clazz.getResourceAsStream("/cn/itcast/my.properties");

    // 如果开头没有'/',表示从当前这个class所在的包中开始查找
    InputStream in2 = clazz.getResourceAsStream("my.properties");
}

你可能感兴趣的:(java基础复习(集合、泛型、IO流、多线程、Junit 、内省 、Properties、 路径问题))