Java基础语法,常用知识复习(4)


上一篇
下一篇

10.泛型(Generic)

10.1泛型的使用

//没有使用泛型
public void test1(){
    ArrayList list = new ArrayList();
    list.add(80);
    list.add(90);
    //类型不安全
    //list.add("Tom");
    for(Object item : list){
        //强转时会出现ClassCastException
        int val = (Integer)item;
        System.out.println(val);
    }
}
//使用了泛型后
public void test2(){
    ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(80);
    list.add(90);
    //编译时,会进行类型检查,保证数据的安全,编译不通过
    //list.add("Tom");
    for(Integer item : list){
        //不需要强转了
        int val = item;
        System.out.println(val);
    }
    Interator<Integer> iterator = list.iterator();
    while(iterator.hasNext()){
        int val = iterator.next();
        System.out.println(val);
    }

}
/**
使用泛型的总结
① 集合接口或集合类在jdk5.0时都修改为带泛型的结构。
② 在实例化集合类时,可以指明具体的泛型类型
③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。比如:add(E e)  --->实例化以后:add(Integer e)
④ 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
⑤ 如果实例化时,没指明泛型的类型。默认类型为java.lang.Object类型。
*/

10.2自定义泛型的使用

10.2.1 自定义泛型类,泛型方法
public interface MyGeneric<K, V>{

}
public class Order <T> {
    int age;
    String name;
    T t;
    T[] arr;
    //这个构造器是错误的
    public Order<T>(){}
    //构造器
    public Order(int age, String name, T t){
        this.age = age;
        this.name = name;
        this.t = t;
        //编译失败
        //T[] arr = new T[10];
        //编译正常(运行时T 必须为Object时才可以正常使用,不然会报类型转换错误)
        //java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
        arr = (T[]) new Object[10];
    }
    //泛型方法
    //[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
    public <E> List<E> copyArrToList(E[] arr){
        List<E> list = new ArrayList<E>();
        for (E e : arr) {
            list.add(e);
        }
        return list;
    }

    //以下并不是泛型方法
    public T getRealAge(){
        return t;
    }
    public T setRealAge(T t){
        T temp = this.t;
        this.t = t;
        return temp;
    }
    //static 的方法中不能声明泛型
    //public static void show(T t){}
}
//泛型不同的引用不能相互赋值
List<Integer> integerList = new ArrayList<>();
//编译报错
//List<Object> objectList = integerList;
//分析,假如正确
//objectList.add(new Object());
//Integer val = integerList.get(0);//试图把 object赋值给Integer (这是不可能的)

10.2.2 子类的泛型
class Father<T1, T2>{}
//子类不保留父类的泛型
//1)没有类型擦除
class Son1 extends Father{
//等价于 class Son1 extends Father<Object, Object>{}
}
//2)具体类型
class Son2 extends Father<Integer, String>{}
//子类保留父类的泛型
//1)全部保留
class Son3<T1, T2> extends Father<T1, T2>{}
//2)部分保留
class Son4<T2> extends Father<Integer, T2>{}
10.2.3 泛型方法
 // [访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常
 //public <T extends Comparable<? super T>> void sort(List<T> list){}
 //表示T必须实现Comparable接口并且 接口的泛型 必须是[T,无穷大)
public static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
    for (T o : a) {
        c.add(o);
    }
}
public static <T> void fromArrayToCollection(Collection<T> c,T[] a) {
    for (T o : a) {
        c.add(o);
    }
}
public static void main(String[] args) {
    Object[] ao = new Object[100];
    Collection<Object> co = new ArrayList<Object>();
    fromArrayToCollection(ao, co);
    String[] sa = new String[20];
    Collection<String> cs = new ArrayList<>();
    fromArrayToCollection(sa, cs);
    Collection<Double> cd = new ArrayList<>();
// 下面代码中T是Double类,但sa是String类型,编译错误。
// fromArrayToCollection(sa, cd);
// 下面代码中T是Object类型,sa是String类型,可以赋值成功。
    fromArrayToCollection(sa, co);
    fromArrayToCollection(co, sa);
    System.out.println(co);
}
10.2.4 泛型在继承上的体现
/**
如果B是A的一个子类型(子类或者子接口),而G是具有泛型声明的
类或接口,G<B>并不是G<A>的子类型!
比如:String是Object的子类,但是List<String >并不是List<Object>
的子类
*/
class Creature{}
class Person extends Creature{}
class Man extends Person{}
class PersonTest {
    //T可以是Person及其子类
    public static <T extends Person> void test(T t){
        System.out.println(t);
    }
    public static void main(String[] args) {
        test(new Person());
        test(new Man());
        //The method test(T) in the type PersonTest is not
        //applicable for the arguments (Creature)
        //test(new Creature());//编译失败
    }

    //对比集合
    public void testGenericAndSubClass() {
        Person[] persons = null;
        Man[] mans = new Man[10];
        // 而 Person[] 是 Man[] 的父类.
        persons = mans;
        Person p = mans[0];
        //编译通过但是运行会失败
        persons[2] = new Person();
        System.out.println(mans[2]);
        // 在泛型的集合上
        List<Person> personList = null;
        List<Man> manList = null;
        //personList = manList;(报错)
    }
}

10.2.5 通配符: ? 的使用
/**
1.使用类型通配符:?
比如:List<?> ,Map<?,?>
List<?>是List<String>、List<Object>等各种泛型List的父类。
2.读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object。
3.写入list中的元素时,不行。因为我们不知道c的元素类型,我们不能向其中添加对象。
   唯一的例外的是null,它是所有类型的成员。
   另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object

4.有限制的通配符
    <? extends Person>   (无穷小 Person]
    <? super Person>  [Person,无穷大)
    <? extends Comparable>  只允许泛型为实现Comparable接口的实现类的引用调用
   */
    public static void main(String[] args) {
        List<?> list = null;
        list = new ArrayList<String>();
        list = new ArrayList<Double>();
        //将任意元素加入到其中不是类型安全的:
        //list.add(3);//编译不通过
        list.add(null);

        List<String> stringList = new ArrayList<>();
        List<Integer> integerList = new ArrayList<>();

        stringList.add("AA");
        stringList.add("BB");
        stringList.add("CC");

        integerList.add(12);
        integerList.add(19);
        integerList.add(20);
        read(stringList);
        read(integerList);
    }

    public static void read(List<?> list){
        for (Object o : list) {
            System.out.println(o);
        }
    }
    public static <T> void test(T t,ArrayList<T> list){}
    //1.编译错误:不能用在泛型方法声明上,返回值类型前面<>不能使用?
    //public static <?> void test(? t,ArrayList<?> list){}
    //2.编译错误:不能用在创建对象上,右边属于创建集合对象
    //ArrayList<?> list2 = new ArrayList<?>();
    //3.编译错误:不能用在泛型类的声明上
    //class GenericTypeClass<?>{}//:编译错误:不能用在泛型类的声明上
    //有限制的通配符
    public static void printCollection(Collection<? extends Person> coll){
        Iterator<? extends Person> iterator = coll.iterator();
        while(iterator.hasNext()){
            //可以是[Person,无穷)
            Person next = iterator.next();
            System.out.println(next);
        }
        //编译报错,coll的泛型可能是更小的
        //coll.add(new Person());
    }
    public static void printCollection2(Collection<? super Person> coll){
        Iterator<? super Person> iterator = coll.iterator();
        while(iterator.hasNext()){
            //只能是Object
            Object next = iterator.next();
            System.out.println(next);
        }
        //可以添加数据  (无穷小,Person]
        coll.add(new Person());
        coll.add(new Man());
    }
    //泛型嵌套
    HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
10.2.5 泛型的例题
/**
开发一个泛型Apple类,要求有一个重量属性weight在测试类中实例化不同的泛型对象,要求对象对象a1的这一属性是Integer型,a2的这一属性是Double型。
分别为a1,a2,a3的重量属性赋值为:500,500.0,在测试类中通过对象调用访问器得到属性值并输出。
*/
public class Apple<T extends Number> {

    private T weight;

    public Apple (T weight){
        this.weight = weight;
    }

    public T getWeight(){
        return weight;
    }

    public void setWeight(T weight){
        this.weight = weight;
    }

}
class TestApple{
    public static void main(String[] args) {
        Apple<Integer> integerApple = new Apple<>(500);
        Apple<Double> doubleApple = new Apple<>(500.0);
        System.out.println(integerApple.getWeight());
        System.out.println(doubleApple.getWeight());
    }
}
/************************************************************************************/
/**
定义个泛型类 DAO<T>,在其中定义一个 Map 成员变量,Map 的键
为 String 类型,值为 T 类型。
分别创建以下方法:
public void save(String id,T entity): 保存 T 类型的对象到 Map 成员
变量中
public T get(String id):从 map 中获取 id 对应的对象
public void update(String id,T entity):替换 map 中 key 为 id 的内容,
改为 entity 对象
public List<T> list():返回 map 中存放的所有 T 对象
public void delete(String id):删除指定 id 对象
定义一个 User 类:
该类包含:private 成员变量(int 类型) id,age;(String 类型)name。
定义一个测试类:
创建 DAO 类的对象, 分别调用其 save、get、update、list、delete 方
法来操作 User 对象,
使用 Junit 单元测试类进行测试。
*/
class TestDao{
    public static void main(String[] args) {
        Dao<Users> usersDao = new Dao<>();
        usersDao.save("zhangsan",new Users("zhangsan",13));
        usersDao.save("lisi",new Users("lisi",29));
        usersDao.save("wangwu",new Users("wangwu",19));
        usersDao.save("tom", new Users("tom", 23));
        List<Users> list = usersDao.list();
        printList(list);
        usersDao.delete("zhangsan");
        System.out.println(usersDao.getSize());
        System.out.println(usersDao.get("lisi"));
    }
    public static void printList(List<?> list){
        for (Object o : list) {
            System.out.println(o);
        }
    }
}
class Dao<T>{
    Map<String, T> map = new HashMap<>();
    public void save(String id,T entity){
        if (map.containsKey(id)){
            throw new RuntimeException("该数据已存在");
        }
        map.put(id, entity);
    }
    public T get(String id){
        return map.get(id);
    }
    public void update(String id,T entity){
        if (map.containsKey(id)){
            map.put(id, entity);
        }
        throw new RuntimeException("数据不存在");
    }
    //返回 map 中存放的所有 T 对象s
    public List<T> list(){
        List<T> list = new ArrayList<>();
        //Set<Map.Entry<String, T>> entries = map.entrySet();
//        for (Map.Entry<String, T> entry : entries) {
//            System.out.println(entry.getKey() + " = " + entry.getValue());
//        }
        Collection<T> values = map.values();
        for (T value : values) {
            list.add(value);
        }
        return list;
    }
    public void delete(String id){
        if (map.containsKey(id)){
            map.remove(id);
        }
    }
    public int getSize(){
        return map.size();
    }
}
class Users{
    private String name;
    private int age;

    public Users(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Users{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Users users = (Users) o;

        if (age != users.age) return false;
        return name != null ? name.equals(users.name) : users.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

11.IO

11.1 File类

1. File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)
2.File类声明在java.io包下
3.File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,
并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成。
4. 后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点".
5.实例化
File(String filePath)
File(String parentPath,String childPath)
File(File parentFile,String childPath)
路径的分类
相对路径:相较于某个路径下,指明的路径。
绝对路径:包含盘符在内的文件或文件目录的路径
6.常用的方法
boolean canExecute() //是否可执行
boolean canRead()//是否能读
boolean canWrite() //是否能写
boolean isFile()//是否是文件
boolean isDirectory();//是否是文件目录
boolean exists() //判断是否存在
boolean createNewFile()//创建文件 如果存在,则不创建 返回false
boolean mkdir()//创建文件目录  存在就不创建了, 如果上层目录不存在则不创建
boolean mkdirs()//创建文件目录  如果上层文件不存在,一并创建
boolean delete()//删除文件或目录,  目录有文件则不删除  删除不走回收站
/**
输出某个文件夹下的所有文件
*/
public static void printFileName(File file){
    if (file.isFile()){
        System.out.println(file);
    }else {
        File[] files = file.listFiles();
        for (File f : files) {
            printFileName(f);
        }
    }
}

11.2 IO流的概述

1.流的分类
①.操作数据单位:字节流,字符流
②.数据的流向:输入流,输出流
③.流的角色:节点流,处理流

2.输入、输出的标准化过程
2.1 输入过程
① 创建File类的对象,指明读取的数据的来源。(要求此文件一定要存在)
② 创建相应的输入流,将File类的对象作为参数,传入流的构造器中
③ 具体的读入过程:
    创建相应的byte[] 或 char[]。
④ 关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理。
2.2 输出过程
① 创建File类的对象,指明写出的数据的位置。(不要求此文件一定要存在)
② 创建相应的输出流,将File类的对象作为参数,传入流的构造器中  此时会创建文件
③ 具体的写出过程:
    write(char[]/byte[] buffer,0,len)
④ 关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理。

流的体系结构
 抽象基类         节点流(或文件流)                               缓冲流(处理流的一种)
 InputStream     FileInputStream   (read(byte[] buffer))        BufferedInputStream (read(byte[] buffer))
 OutputStream    FileOutputStream  (write(byte[] buffer,0,len)  BufferedOutputStream (write(byte[] buffer,0,len) / flush()
 Reader          FileReader (read(char[] cbuf))                 BufferedReader (read(char[] cbuf) / readLine())
 Writer          FileWriter (write(char[] cbuf,0,len)           BufferedWriter (write(char[] cbuf,0,len) / flush()

image

11.3 节点流(文件流)的示例代码

/**
FileReader/FileWriter/FileOutputStream/FileInputStream
读入的文件一定要存在,否则就会报FileNotFoundException。
*/
public static void testFileReaderAndFileWriter(){
    FileWriter fileWriter = null;
    FileReader fileReader = null;
    try {
        //创建流
        fileWriter = new FileWriter(new File("java_base4" + File.separator + "copy.txt"));
        fileReader = new FileReader(new File("java_base4" + File.separator + "hello.txt"));
        char[] c = new char[3];
        int temp = -1;
        //读加写
        while ((temp = fileReader.read(c)) != -1){
            fileWriter.write(c, 0 ,temp);
        }
        //刷新
        fileWriter.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //关闭流
        if (fileReader != null){
            try {
                fileReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (fileWriter != null){
            try {
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

public static void testFileInputStreamAndFileOutputStream(){
    long start = System.currentTimeMillis();
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        fis = new FileInputStream("java_base4" + File.separator + "test.jpg");
        fos = new FileOutputStream("java_base4" + File.separator + "test_bak.jpg");
        int temp = -1;
        byte[] b = new byte[10];
        while ((temp = fis.read(b)) != -1){
            fos.write(b, 0, temp);
        }
        fos.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fis != null){
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (fos != null){
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    long end = System.currentTimeMillis();
    System.out.println("用时:" + (end -start));
}

11.4 缓冲流的示例代码

/**
 * 1.缓冲流:
 * BufferedInputStream
 * BufferedOutputStream
 * BufferedReader
 * BufferedWriter
 * 2.作用:提供流的读取、写入的速度
 *   提高读写速度的原因:内部提供了一个缓冲区
 *
 * 3. 处理流,就是“套接”在已有的流的基础上。
 */
public static void testBufferedReaderAndBufferedWriter(){
    BufferedReader br = null;
    BufferedWriter bw = null;
    try {
        br = new BufferedReader(new FileReader("java_base4" + File.separator + "hello.txt"));
        bw = new BufferedWriter(new FileWriter("java_base4" + File.separator + "copy.txt",true));
        String s = null;
        while ((s = br.readLine()) != null){
            bw.write(s);
            bw.newLine();
        }
        bw.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(bw != null){
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(br != null){
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
public static void testBufferedInputStreamAndBufferedOutputStream(){
    long start = System.currentTimeMillis();
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try {
        bis = new BufferedInputStream(new FileInputStream("java_base4" + File.separator + "test.jpg"));
        bos = new BufferedOutputStream(new FileOutputStream("java_base4" + File.separator + "test_bak_x.jpg"));
        byte[] bytes = new byte[10];
        int temp = -1;
        while ((temp = bis.read(bytes)) != -1){
            bos.write(bytes, 0, temp);
        }
        bos.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(bis != null){
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(bos != null){
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    long end = System.currentTimeMillis();
    System.out.println("X用时:" + (end -start));
}

11.5 转换流的示例代码

/**
 * 处理流之二:转换流的使用
 * 1.转换流:属于字符流
 *   InputStreamReader:将一个字节的输入流转换为字符的输入流
 *   OutputStreamWriter:将一个字节的输出流转换为字符的输出流
 * 2.作用:提供字节流与字符流之间的转换
 * 3. 解码:字节、字节数组  --->字符数组、字符串
 *    编码:字符数组、字符串 ---> 字节、字节数组
 *
 *
*/
//读写相关的应用
public void test2() throws Exception {
    //1.造文件、造流
    File file1 = new File("dbcp.txt");
    File file2 = new File("dbcp_gbk.txt");
    FileInputStream fis = new FileInputStream(file1);
    FileOutputStream fos = new FileOutputStream(file2);
    InputStreamReader isr = new InputStreamReader(fis,"utf-8");
    OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
    //2.读写过程
    char[] cbuf = new char[20];
    int len;
    while((len = isr.read(cbuf)) != -1){
        osw.write(cbuf,0,len);
    }
    //3.关闭资源
    isr.close();
    osw.close();
}

//转换流,缓冲流,标准输入流的应用
public class MyScanner {

    public static void main(String[] args) {
        MyScanner myScanner = new MyScanner(System.in);
        String s = myScanner.readString();
        System.out.println(s);
    }
    BufferedReader br = null;
    MyScanner(InputStream inputStream){
        InputStreamReader reader = new InputStreamReader(inputStream);
        br = new BufferedReader(reader);
    }

    public String readString() {

        // Declare and initialize the string
        String string = "";

        // Get the string from the keyboard
        try {
            string = br.readLine();

        } catch (IOException ex) {
            System.out.println(ex);
        }

        // Return the string obtained from the keyboard
        return string;
    }

    // Read an int value from the keyboard
    public  int readInt() {
        return Integer.parseInt(readString());
    }

    // Read a double value from the keyboard
    public  double readDouble() {
        return Double.parseDouble(readString());
    }

    // Read a byte value from the keyboard
    public  double readByte() {
        return Byte.parseByte(readString());
    }

    // Read a short value from the keyboard
    public  double readShort() {
        return Short.parseShort(readString());
    }

    // Read a long value from the keyboard
    public  double readLong() {
        return Long.parseLong(readString());
    }

    // Read a float value from the keyboard
    public  double readFloat() {
        return Float.parseFloat(readString());
    }

    public void close() throws IOException {
        if (br != null){
            br.close();
        }
    }
}

11.5 其他流

/**
 * 其他流的使用
 * 1.标准的输入、输出流
 *     System.in(默认从键盘输入)  System.out(默认从控制台输出)
 *     System类的setIn(InputStream is) / setOut(PrintStream ps)方式重新指定输入和输出的流
 * 2.打印流  PrintStream 和PrintWriter
 * 3.数据流  DataInputStream 和 DataOutputStream
 */
/*
1.3练习:
从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,
直至当输入“e”或者“exit”时,退出程序。
方法一:使用Scanner实现,调用next()返回一个字符串
方法二:使用System.in实现。System.in  --->  转换流 ---> BufferedReader的readLine()
*/
public static void main(String[] args) {

    //System.setIn();
    System.out.println("开始输入你的文章:");
    PrintStream ps = null;
    MyScanner my = null;
    try {
        //打印流
        //ps = new PrintStream("java_base4\\小说.txt");
        // 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
        ps = new PrintStream(new FileOutputStream("java_base4\\小说.txt"),true);
        //重置打印流
        System.setOut(ps);
        //读取键盘输入的内容
        my = new MyScanner(System.in);
        while (true){
            String s = my.readString();
            if ("e".equalsIgnoreCase(s) || "exit".equalsIgnoreCase(s)){
                break;
            }
            System.out.println(s);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (ps != null){
            ps.close();
        }
        if (my != null){
            try {
                my.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

//数据流的使用
//将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。
//注意点:读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致!
public static void testDataStream() throws Exception{
    FileOutputStream fos = new FileOutputStream("java_base4\\my.dat");//文件已经创建好了
    FileInputStream fis = new FileInputStream("java_base4\\my.dat");
    DataInputStream dis = new DataInputStream(fis);
    DataOutputStream dos = new DataOutputStream(fos);
    dos.writeBoolean(true);
    dos.writeUTF("果冻");
    dos.writeInt(18);
    dos.writeFloat(10.0f);
    dos.flush();
    boolean b = dis.readBoolean();
    String name = dis.readUTF();
    int age = dis.readInt();
    float v = dis.readFloat();
    System.out.println("性别 : " + b);
    System.out.println("姓名 : " + name);
    System.out.println("年龄 : " + age);
    System.out.println("浮点数 : " + v);
    dos.close();
    dis.close();
}

11.6 对象流 ObjectInputStream/ObjectOutputStream

1.作用:
ObjectOutputStream:内存中的对象--->存储中的文件、通过网络传输出去:序列化过程
ObjectInputStream:存储中的文件、通过网络接收过来 --->内存中的对象:反序列化过程
2.对象的序列化机制:
对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘
上,或通过网络将这种二进制流传输到另一个网络节点。//当其它程序获取了这种二进制流,就可以恢复成原来的
Java对象
//代码示例
public class ObjectStream {
    public static void main(String[] args) throws Exception{
        testObjectStream();
    }

    public static void testObjectStream () throws Exception{
        //ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("java_base4\\object.dat"));
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("java_base4\\object.dat"));
        //oos.writeObject(new Person("张三", 18, "我是个学生"));
        //oos.close();
        Object o = ois.readObject();
        System.out.println(o);
        ois.close();
    }
}
/**
 * Person需要满足如下的要求,方可序列化
 * 1.需要实现接口:Serializable
 * 2.当前类提供一个全局常量:serialVersionUID 不提供的化 每次编译都会随机默认一个serialVersionUID 的值 反序列化时 就会失败
 * 3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性
 *   也必须是可序列化的。(默认情况下,基本数据类型可序列化)
 *
 *
 * 补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
 */
class Person implements Serializable {
    private static final long serialVersionUID = 1L;

    public Person(String name, int age, String content) {
        this.name = name;
        this.age = age;
        this.content = content;
    }

    private String name;

    private int age;

    private transient String content;//transient 短暂的 不能被序列化

    static Double debal;//静态变量不能被序列化

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", content='" + content + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

11.7 随机存取文件流:RandomAccessFile

/**
* 1.RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
* 2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
*
* 3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
*   如果写出到的文件存在,则会对原文件内容进行覆盖。(默认情况下,从头覆盖)
*
* 4. 可以通过相关的操作,实现RandomAccessFile“插入”数据的效果。seek(int pos)

*/
public class RandomAccessFileTest {
    public static void main(String[] args) {
        insterValue(6,"xyz");
    }

    public static void insterValue(int index, String context){

        RandomAccessFile rafInput = null;
        ByteArrayOutputStream outputStream = null;
        try {
            rafInput = new RandomAccessFile("java_base4\\hello.txt", "rw");
            rafInput.seek(index);
            byte[] b = new byte[5];
            int temp = -1;
            //StringBuilder sb = new StringBuilder(context);
            outputStream = new ByteArrayOutputStream();
            while ((temp = rafInput.read(b)) != -1){
                //sb.append(new String(b, 0, temp));
                outputStream.write(b, 0 ,temp);
            }
            outputStream.flush();
            //重置指针
            rafInput.seek(index);
            rafInput.write(context.getBytes());
            rafInput.write(outputStream.toByteArray());
            //rafInput.write(sb.toString().getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (rafInput != null){
                try {
                    rafInput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

12. 网络编程

12.1 InetAddress类的使用

一、实现网络通信需要解决的两个问题
 1.如何准确地定位网络上一台或多台主机;定位主机上的特定的应用
 2.找到主机后如何可靠高效地进行数据传输
二、网络通讯的两个要素
 1.对应问题一: IP 和端口号
 2.对应问题二:提供网络通讯协议: UCP/IP参考模型(应用层、传输层、网络层、物理+数据链路层)
三、通信要素一:IP和端口号
1.IP的理解
 1). IP:唯一的标识 Internet 上的计算机(通信实体)
 2). 在Java中使用InetAddress类代表IP(此类的一个对象就代表着一个具体的IP地址)
 3). IP分类:IPv4 和 IPv6 ; 万维网 和 局域网
 4). 域名:   www.baidu.com   www.mi.com  www.sina.com  www.jd.com
域名解析:域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接。 -------域名解析
 5).本地回路地址 127.0.0.1对应着:localhost
2.
实例化:InetAddress.getByName(),InetAddress.getLocalHost()
常用方法: getHostNaem(); getHostAddress();
3.端口号
* 要求:不同的进程不同的端口号
* 范围:被规定为一个 16 位的整数 0~65535。
端口号与IP地址的组合得出一个网络套接字:Socket

四、通信要素二:网络通信协议
见下图
  1. 分型模型
    image
    2.TCP和UDP的区别
    image
    3.TCP三次握手和四次挥手
    image
    image
//代码示例
public static void main(String[] args) {
    try {
        InetAddress inet1 = InetAddress.getByName("192.168.10.14");
        System.out.println(inet1);//    /192.168.10.14
        InetAddress inet2 = InetAddress.getByName("mobdev.dhcccloud.com.cn");//mobdev.dhcccloud.com.cn/60.171.122.223
        InetAddress inet5 = InetAddress.getByName("test.dhcccloud.com.cn");//test.dhcccloud.com.cn/60.171.122.223
        System.out.println("--------------" + inet2);
        System.out.println("--------------" + inet5);
        InetAddress inet3 = InetAddress.getByName("localhost");
        System.out.println(inet3);
        //获取本地ip
        InetAddress inet4 = InetAddress.getLocalHost();
        System.out.println(inet4);
        //getHostName()
        System.out.println("hostname" + inet2.getHostName());
        //getHostAddress()
        System.out.println("hostaddress" + inet2.getHostAddress());
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } finally {
    }
}

12.2 TCP网络编程 示例代码

public class TpcTest {

    //客户端
    @Test
    public void client(){
        Socket socket = null;
        OutputStream outputStream = null;
        BufferedInputStream bufferedInputStream = null;
        BufferedInputStream inputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            //连接服务端Socket
            socket = new Socket("localhost", 9999);
            outputStream = socket.getOutputStream();
            bufferedInputStream = new BufferedInputStream(new FileInputStream("test.jpg"));
            byte[] buffb = new byte[1024];
            int temp = -1;
            while ((temp = bufferedInputStream.read(buffb)) != -1){
                outputStream.write(buffb, 0, temp);
            }
            outputStream.flush();
            //给服务器说停止本次传输了
            socket.shutdownOutput();
            //获取输入流,读取服务器端返回消息
            inputStream = new BufferedInputStream(socket.getInputStream());
            //使用byteArrayOutputStream 流来接收,防止控制台打印时乱码
            byteArrayOutputStream = new ByteArrayOutputStream();
            while ((temp = inputStream.read(buffb)) != -1){
                byteArrayOutputStream.write(buffb, 0, temp);
            }
            byteArrayOutputStream.flush();

            System.out.println(new String(byteArrayOutputStream.toByteArray()));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            if(byteArrayOutputStream != null){
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(bufferedInputStream != null){
                try {
                    bufferedInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    //服务器端
    @Test
    public void service(){
        Socket socket = null;
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        BufferedOutputStream outputStream = null;
        try {
            //创建服务端ServerScoket
            ServerSocket serverSocket = new ServerSocket(9999);
            //获取连接
            socket = serverSocket.accept();
            //获取输入流
            bufferedInputStream = new BufferedInputStream(socket.getInputStream());
            //本地输出流
            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("hhh.jpg"));
            byte[] buffb = new byte[1024];
            int temp = -1;
            //通过输入流读取数据并下载到本地
            while ((temp = bufferedInputStream.read(buffb)) != -1){
                bufferedOutputStream.write(buffb, 0, temp);
            }
            bufferedOutputStream.flush();
            //返回消息
            outputStream = new BufferedOutputStream(socket.getOutputStream());
            String message = "你好图片已接受到";
            outputStream.write(message.getBytes());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(bufferedInputStream != null){
                try {
                    bufferedInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(bufferedOutputStream != null){
                try {
                    bufferedOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

12.3 UDP网络编程 示例代码

public class UDPTest {
    @Test
    public void client(){
        DatagramSocket socket = null;
        try {
            socket = new DatagramSocket();

            String content = "我是发送的内容,短信轰炸!!!";
            //组包
            InetAddress localhost = InetAddress.getByName("localhost");
            DatagramPacket packet = new DatagramPacket(content.getBytes(), 0, content.getBytes().length, localhost, 9999);
            socket.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //socket.disconnect();
            if(socket != null)
            socket.close();
        }
    }

    @Test
    public void service(){
        DatagramSocket socket = null;
        try {
            socket = new DatagramSocket(9999);
            byte[] buffer = new byte[200];//要确保数据可以放下
            DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
            //接收消息
            socket.receive(packet);
            System.out.println(new String(packet.getData(),0,packet.getLength()));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null)
                socket.close();
        }

    }
}

12.4 URL网络编程

/**
 * 1.URL:统一资源定位符,对应着互联网的某一资源地址
 * 2.格式:
 *  http://localhost:8080/examples/beauty.jpg?username=Tom
 *  协议   主机名    端口号  资源地址           参数列表
 * 3.实例化URL
 * URL url = new URL(http://localhost:8080/examples/beauty.jpg?username=Tom);
 * 4.常用的方法
 * public String getProtocol();//获取协议 http
 * public String getHost();// 获取主机名 localhost
 * public String getPort();//获取端口 8080
 * public String getPath();//获取文件路径 /examples/beauty.jpg
 * public String getFile();//获取文件名 /examples/beauty.jpg?username=Tom
 * public String getQuery();//获取查询名 username=Tom
*/
public void test(){
    HttpURLConnection urlConnection = null;
    InputStream inputStream = null;
    BufferedOutputStream outputStream = null;
    try {
        //创建URL对象
        URL url = new URL("https://q-extra.paixin.com/default/2021/0305/7c2a435bc69e61d62124b1fc4d28caeb.jpg");
        //打开连接
        urlConnection = (HttpURLConnection) url.openConnection();
        //连接
        urlConnection.connect();
        //获取输入流
        inputStream = urlConnection.getInputStream();
        //获取文件
        String file = url.getFile();//   /default/2021/0305/7c2a435bc69e61d62124b1fc4d28caeb.jpg
        String[] split = file.split("\\.");
        outputStream = new BufferedOutputStream(new FileOutputStream("aaa." + split[1]));
        int temp = -1;
        byte[] bytes = new byte[1024];
        //开始下载文件
        while ((temp = inputStream.read(bytes)) != -1){
            outputStream.write(bytes,0, temp);
        }
        outputStream.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //关闭资源
        if(outputStream != null){
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(inputStream != null){
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(urlConnection != null){
            urlConnection.disconnect();
        }
    }
}
posted @ 2021-06-20 10:37  爱做梦的猪猪怪  阅读(55)  评论(0)    收藏  举报