阶段一:java基础篇04

目录

一、Java集合

二、IO流

三、泛型

四、网络编程

 

一、Java集合

1、Java集合概述

  • 集合就是对数据进行储存的容器,这里的储存是指在内存中的储存,持久化的储存在之后的SQL中会学到。
  • 解决数组存储数据方面的弊端。

       java集合与数组的比较

  • 数组长度定义后不可变,集合可变
  • 数组只能存储相同类型元素,集合可以存储不同的数据类型
  • 数组中提供的方法优先,集合中有各种各样的方法对数据进行操作

 

2、集合分类

 

常用的集合:

  •     Collection接口:用来存储一个一个的对象
    • List接口:存储有序的可重复的数据
      • ArrayList
      • LinkedList
      • Vector
    • Set接口:存储无序的,不可重复的数据
      • HashSet
      • LinedHashSet
      • TreeSet
  •     Map接口:用来储存key—value对的数据
    • HashMap
      • LinedHashMap
    • TreeMap
    • HashTable

 

3、Collection接口

  • 用来存储一个一个的数据
  • 向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals()
  • 有list和set实现接口

 

  • Collection接口常用方法:
    • add(Object obj)      向集合添加元素,若操作成功返回true
    • addAll(Collection coll)    向集合添加所有元素,成功返回true
    • size()   集合元素个数     
    • isEmpty()   是否为空
    • clear()     清空集合
    • contains(Object obj)   判断集合是否包含obj
    • containsAll(Collection coll)    判断集合是否包含coll中所有元素
    • remove(Object obj)      从集合中删除一个指定元素
    • removeAll(Collection coll)   从集合中删除所有在集合 coll 中出现的元素
    • retainsAll(Collection coll)   从集合中删除集合 coll 里不包含的元素

集合与数组的转换:

  • 集合转数组:collection1.toArray()
  • 数组转集合:Arrays.asList()

List接口:存储有序的,可重复的数据

  • ArrayList:list接口主要实现类,线程不安全,效率高,底层用Object数组存储

             JDK1.7new的时候底层创建长度为10的Object数组,默认情况下扩容为原来的1.5倍

             JDK1.8new时的底层中数组初始化为{},第一次调用add()时,底层才创建长度10的数组,扩容为原来的1.5倍

  • LinkedList:底层使用双向链表储存,频繁删除插入操作效率高

             新建对象时,内部声明了Node类型的first和last属性,默认值为null

  • Vector:List接口古老实现类,线程安全,效率低,底层也用Object数组储存

            jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组。默认扩容为原来的2倍。

 

常用方法

  • 增:add(Object obj)
  • 删:
    • remove(int index) 
    • remove(Object obj)
  • 改:set(int index, Object obj)
  • 查:get(int index)
  • 插:add(int index, Object obj)
  • 长度:size()
  • 遍历:
    • Iterator
    • 增强for循环
    • 普通的循环

 

Set接口:存储无序的,不可重复的数据

  • HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值
  • LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历                  
  • TreeSet:可以照添加对象的指定属性,进行排序。(自然排序、定制排序)

元素添加的过程(HashSet举例)

HashSet底层:JDK1.7 数组+链表   (底层用的HashMap创建的...)

 

  • 添加元素,先调用元素hashCode方法,得到hash值
  • 根据hash值通过某种算法来计算出在底层中的存放位置,
    • 如果HashSet位置上无元素,直接添加
    • 如果位置上已经有元素的情况下,比较元素之间的hash值
      • 若hash值都不同,就添加成功
      • 若hash值相同,就调用元素所在类的equals()方法
        • equals方法返回false,添加成功
        • equals方法返回true,添加失败

注意:向Set(主要指:HashSet、LinkedHashSet)中添加的数据,其所在的类一定要重写hashCode()和equals()

 

4、Map接口:存储key—value的数据

  • Map
    •  HashMap:作为Map的主要实现类,线程不安全的,效率高;存储null的key和value
      • LinkedHashMap:保证在遍历map元素时,可以照添加的顺序实现遍历,
    • TreeMap:以添加的key-value对进行排序。此时考虑key的自然排序或定制排序,要求key必须是由同一个类创建的对象
    • HashTable:作为古老的实现类;线程安全的,效率低;不能存储null的key和value
      • Properties:配置文件常用 (key=value)

Map(key,value):   构成Entry对象

  • key:  无序的不可重复的,用set储存 ,key所在类重写equals()和hashcode()方法
  • value: 无序的可重复的,用Collection储存,value所在类重写equal()方法

HashMap底层原理:(jdk1.7)

  • 在实例化后创建长度为16的Entry[]数组
  • 添加元素流程
    • 计算所在类hashcode()方法,并找位置
    • 若位置数据为空,添加成功
    • 若位置不为空,与该位置上所有元素比较hash值
      • 若哈希值都不同,添加成功
      • 若哈希值有一个相同,则比较该类equals方法
        • equals返回true,添加失败
        • equals返回false,添加成功
  • 扩容:默认扩容为原来容量的两倍
  • 底层结构:数组+链表。

HashMap在JDK1.8的变化:

  • new HashMap():底层没创建一个长度为16的数组
  • jdk 8底层的数组是:Node[],而非Entry[]
  • 首次调用put()方法时,底层创建长度为16的数组
  • jdk8中底层结构:数组+链表+红黑树。
  • 形成链表时,七上八下(jdk7:新的元素指向旧的元素。jdk8:旧的元素指向新的元素)
  • 当数组某一个链表长度大于8,且数组长度大于64时,将该位置下的链表改为红黑树存储
    • DEFAULT_INITIAL_CAPACITY : HashMap默认容量:16
    • DEFAULT_LOAD_FACTOR:HashMap默认加载因子:0.75
    • threshold:扩容临界值 = 容量 * 加载因子 
    • TREEIFY_THRESHOLD: 数组某一元素中的链表长度大于该默认值,转化为红黑树 : 8
    • MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64

 

常用方法:

  • 添加:put(Object key,Object value)
  • 删除:remove(Object key)
  • 修改:put(Object key,Object value)
  • 查询:get(Object key)
  • 长度:size()
  • 遍历:keySet() / values() / entrySet()
  •  

5、Collections工具类

用来操作Collection和Map的工具类

 

  • reverse(List):反转 List 中元素的顺序
  • shuffle(List):对 List 集合元素进行随机排序
  • sort(List):根据元素的自然顺序对指定 List 集合元素升序排序
  • sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
  • swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
  • Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
  • Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
  • Object min(Collection)
  • Object min(Collection,Comparator)
  • int frequency(Collection,Object):返回指定集合中指定元素的出现次数
  • void copy(List dest,List src):将src中的内容复制到dest中
  • boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所旧值

注:ArrayList和HashMap都是线程不安全的,如果程序要求线程安全,我们可以将ArrayList、HashMap转换为线程的。
使用synchronizedList(List list) 和 synchronizedMap(Map map)

 

二、IO流

 

1、IO流概念

我们需要读取计算机上的文件信息,对于计算机来说,我们读取到的数据都是“100100101110”的字节数据,如何将数据读取出来呢,就需要一个管道,将文件中的数据以类似字节流的方式进行读取出来

流的分类:

  • 按操作数据单位:字节流、字符流
  • 数据的流向:输入流、输出流
  • 流的角色:节点流、处理流

流的体系结构:

  • 抽象基类
  • 访问文件
  • 访问数组
  • 缓冲流
  • 转化流
  • 对象流
  • 打印流等

学习IO流,首先我们需要了解file类

2、File类

  1. 一个文件或者一个目录都可以称为一个File类的对象
  2. File类在java.io包下
  3. File类中涉及到有关文件的创建、删除、重命名、修改时间、文件大小等方法,写入、读取操作由IO流来实现
  4. File有多个重载的构造器

File方法:

  

 

3、节点流

  ①、FileReader/FileWriter的使用  字节流

public void testFileReaderFileWriter() {
        FileReader fr = null;
        FileWriter fw = null;
        try {
            //1.创建File类的对象,指明读入和写出的文件
            File srcFile = new File("hello.txt");
            File destFile = new File("hello2.txt");

            //不能使用字符流来处理图片等字节数据

            //2.创建输入流和输出流的对象
             fr = new FileReader(srcFile);
            fw = new FileWriter(destFile);


            //3.数据的读入和写出操作
            char[] cbuf = new char[5];
            int len;//记录每次读入到cbuf数组中的字符的个数
            while((len = fr.read(cbuf)) != -1){
                //每次写出len个字符
                fw.write(cbuf,0,len);

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关闭流资源
            //方式二:
            try {
                if(fw != null)
                    fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if(fr != null)
                    fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

 ②FileInputStream / FileOutputStream的使用  字符流

public void testFileInputOutputStream()  {
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        //1.建文件
        File srcFile = new File("1.jpg");
        File destFile = new File("2.jpg");

        //2.建流
        fis = new FileInputStream(srcFile);
        fos = new FileOutputStream(destFile);

        //3.复制的过程
        byte[] buffer = new byte[5];
        int len;
        while((len = fis.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.关流
        if(fos != null){
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(fis != null){
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

}

 

4、缓冲流

提供流的读取、写入的速度,内存中提供一个缓冲区,默认8kb

 

  • BufferedInputStream
  • BufferedOutputStream
//实现文件复制的方法
    public void copyFileWithBuffered(String srcPath,String destPath){
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        try {
            //1.造文件
            File srcFile = new File(srcPath);
            File destFile = new File(destPath);
            //2.造流
            //2.1 造节点流
            FileInputStream fis = new FileInputStream((srcFile));
            FileOutputStream fos = new FileOutputStream(destFile);
            //2.2 造缓冲流
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);

            //3.复制的细节:读取、写入
            byte[] buffer = new byte[1024];
            int len;
            while((len = bis.read(buffer)) != -1){
                bos.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.流的关闭
            //先关闭外层的流
            if(bos != null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
            if(bis != null){
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
            //关闭外层流的同时,内层流也会自动的进行关闭.我们可以省略
//        fos.close();
//        fis.close();
        }
    }
  • BufferedReader
  • BufferedWriter
public void testBufferedReaderBufferedWriter(){
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            //创建文件和相应的流
            br = new BufferedReader(new FileReader(new File("dbcp.txt")));
            bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));

            //读写操作
            //方式二:使用String
            String data;
            while((data = br.readLine()) != null){
                //方法二:
                bw.write(data);//data中不包含换行符
                bw.newLine();//提供换行的操作

            }


        } 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();
                }

            }
        }

    }

5、转换流

提供字节流与字符流之间的转换

  • InputStreamReader:将一个字节的输入流转换为字符的输入流
  • OutputStreamWriter:将一个字符的输出流转换为字节的输出流
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();


}

6、其他流

①、标准的输入输出流:

  • System.in:标准的输入流,默认从键盘输入
  • System.out:标准的输出流,默认从控制台输出

②、打印流:用于多种数据类型的输出

  • PrintStream
  • PrintWriter

③、数据流:用于读取或写出基本数据类型的变量或字符串

  • DataInputStream
  • DataOutputStream

④、对象流:

  • ObjectOutputStream:内存中的对象--->存储中的文件、通过网络传输出去:序列化过程
  • ObjectInputStream:存储中的文件、通过网络接收过来 --->内存中的对象:反序列化过程

实现序列化的对象所属的类需要满足:

  1. 需要实现接口:Serializable
  2. 当前类提供一个全局常量:serialVersionUID
  3. 除了当前Person类需要实现Serializable接口之外,还必须保证其内部所属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)

补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量

7、其他数据传输API

①随机存取文件流:RandomAccessFile

  • RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
  • RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
    • 如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
    • 如果写出到的文件存在,则会对原文件内容进行覆盖。(默认情况下,从头覆盖)

②Path类(jdk7+)

  • Path替换原有的File类。
  • 常用方法

三、泛型(JDK1.5+)

1、泛型的概念

泛型允许在定义类、接口的时候,通过一个标志来设定模糊的参数类型,可以是返回值类型,也可以是传入参数类型。当对象创建时才能确定到底创建的什么类型的数据。

 

2、泛型的使用

示例:①List<Integer> list =  new List<Integer>();

           ②Set<Map.Entry<String,Integer>> entry = map.entrySet();

  • 在<>里来设定传入的参数类型,定义好后就只能传入该数据类型的变量,否则就会报错。
  • 在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。
  • 泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
  • 如果实例化时没有声明泛型类型,默认为java.long.Object类型

 

3、自定义泛型

泛型类:在类定义后定义泛型 类的内部结构就可以使用类的泛型

public class Order<T> {

    String Name;
    int Id;

    //类的内部结构就可以使用类的泛型

    T orderT;
}

泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没任何关系。

 public static <E>  List<E> myMethod(E[] arr){

        ArrayList<E> list = new ArrayList<>();

        for(E e : arr){
            list.add(e);
        }
        return list;

}

//如下的不是泛型方法
    public T getOrderT(){
        return orderT;
}

4、泛型的特性

  1. 泛型可能有多个参数,此时应该将多个参数一起放入<>中,<E1,E2,E3>​​​​​​​
  2. 泛型的构造器没有<E>,
  3. 泛型不同的引用不能相互赋值
  4. ArrayList<String>和ArrayList<Integer>在编译时时两种类型,但是在运行时刻,只有一个ArrayList被加载到JVM中
  5. 泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
  6. 异常类没有泛型
  7. 父类有泛型,子类可以保留父类泛型,也可以选择指定泛型类型。
  8.  虽然类A是类B的父类,但是G<A> 和G<B>二者不具备子父类关系,二者是并列关系。

  9. 补充:类A是类B的父类,A<G> 是 B<G> 的父类

 

5、泛型中的通配符

   通配符:?

  • 类A是类B的父类,G<A>和G<B>是没关系的,二者共同的父类是:G<?>


    限制条件的通配符的使用

  • ? extends A:
    • G<? extends A> 可以作为G<A>和G<B>的父类,其中B是A的子类
  • ? super A:
    • G<? super A> 可以作为G<A>和G<B>的父类,其中B是A的父类
       

四、网络编程

1、网络编程的概念

①实现网络通信需要解决的两个问题

  1. ​​​​​​​如何准确定位一台或多台主机     ----->   IP和端口号
  2. 如何找到主机后可以可靠的进行数据传输     -----> 网络协议:TCP/IP

 

IP:

  • IP唯一标识一台主机,在java中用InetAddress表示IP地址。
  • InetAddress:
    • 实例化:getByName(String host) 、 getLocalHost()
    • 常用的方法:getHostName() 、 getHostAddress()

端口号:

  • 在计算机中运行的进行编号,不同进程不同的端口号,0~65535

IP+端口号 = Socket

 

TCP协议:

  • 通信前进行TCP连接,三次握手,保证可靠通信
  • 连接成功后可进行稳定的数据传输
  • 传输完成后四次挥手,断开连接
  • TCP特点:可靠性高、效率低

UDP协议:

  • 将数据、源、目的封装成数据包、不需要建立连接
  • 每个数据报大小为64K以内
  • 可以进行广播发送,是否发送成功,发送方不知道。
  • UDP特点:无需释放资源,速度快,开销小,可靠性低

           

             

            

 

 

2、TCP网络编程

这里用康师傅的原生代码!!!

//客户端
    @Test
    public void client()  {
        Socket socket = null;
        OutputStream os = null;
        try {
            //1.创建Socket对象,指明服务器端的ip和端口号
            InetAddress inet = InetAddress.getByName("192.168.14.100");
            socket = new Socket(inet,8899);
            //2.获取一个输出流,用于输出数据
            os = socket.getOutputStream();
            //3.写出数据的操作
            os.write("你好,我是客户端mm".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.资源的关闭
            if(os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }



    }
    //服务端
    @Test
    public void server()  {

        ServerSocket ss = null;
        Socket socket = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            //1.创建服务器端的ServerSocket,指明自己的端口号
            ss = new ServerSocket(8899);
            //2.调用accept()表示接收来自于客户端的socket
            socket = ss.accept();
            //3.获取输入流
            is = socket.getInputStream();

            //不建议这样写,可能会乱码
//        byte[] buffer = new byte[1024];
//        int len;
//        while((len = is.read(buffer)) != -1){
//            String str = new String(buffer,0,len);
//            System.out.print(str);
//        }
            //4.读取输入流中的数据
            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[5];
            int len;
            while((len = is.read(buffer)) != -1){
                baos.write(buffer,0,len);
            }

            System.out.println(baos.toString());

            System.out.println("收到了来自于:" + socket.getInetAddress().getHostAddress() + "的数据");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(baos != null){
                //5.关闭资源
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(ss != null){
                try {
                    ss.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }

3、UDP网络编程

//发送端
@Test
public void sender() throws IOException {

    DatagramSocket socket = new DatagramSocket();



    String str = "我是UDP方式发送的导弹";
    byte[] data = str.getBytes();
    InetAddress inet = InetAddress.getLocalHost();
    DatagramPacket packet = new DatagramPacket(data,0,data.length,inet,9090);

    socket.send(packet);

    socket.close();

}
//接收端
@Test
public void receiver() throws IOException {

    DatagramSocket socket = new DatagramSocket(9090);

    byte[] buffer = new byte[100];
    DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);

    socket.receive(packet);

    System.out.println(new String(packet.getData(),0,packet.getLength()));

    socket.close();
}

4、URL编程

  • URL(Uniform Resource Locator):统一资源定位符,对应着互联网的某一资源地址
  • url结构: http://localhost:8080/llj/index.html?username=Tom

                        协议    主机名    端口号   资源地址          参数列表

  • url对象常用的方法:

public static void main(String[] args) {

    HttpURLConnection urlConnection = null;
    InputStream is = null;
    FileOutputStream fos = null;
    try {
        URL url = new URL("http://localhost:8080/examples/1.jpg");

        urlConnection = (HttpURLConnection) url.openConnection();

        urlConnection.connect();

        is = urlConnection.getInputStream();
        fos = new FileOutputStream("llj\\1.jpg");

        byte[] buffer = new byte[1024];
        int len;
        while((len = is.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }

        System.out.println("下载完成");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //关闭资源
        if(is != null){
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(fos != null){
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(urlConnection != null){
            urlConnection.disconnect();
        }
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值