java基础知识02

作者: 贪挽懒月 | 来源:发表于2018-10-31 12:17 被阅读12次

    前言:

    接着《java基础知识01》,再来聊聊剩下的那些知识点。

    一、java基础类库:

    1、String字符串:
    字符串一旦被初始化,就不可以被改变,存放在方法区中的常量池中。用length()方法获取长度。

    2、StringBuffer字符串缓冲区:
    特点:

    • 可以对字符串内容进行修改。
    • 是一个容器。
    • 是可变长度的。
    • 缓冲区中可以存储任意类型的数据。
    • 最终需要变成字符串。

    容器通常具备一些固定的方法:append()、insert()、delete()、replace()等。

    3、StringBuilder字符串缓冲区:
    JDK1.5出现StringBuiler;与StringBuffer区别如下:

    • StringBuffer线程安全,StringBuilder线程不安全。
    • 单线程操作,使用StringBuilder 效率高。多线程操作,使用StringBuffer 安全。

    4、包装类:
    注意int ---> Integer 和 char ---> Character,这两个基本类型对应的包装类不是首字母大写就可以,其他的对应的包装类都是首字母大写,注意区分。

    5、Collections:
    操作集合的工具类,提供了大量的操作集合的方法,十分方便,且方法都是静态方法。

    6、Arrays:
    操作数组的工具类,提供了大量的操作数组的方法,里面的也都是静态方法。看下面这个常用方法:
    asList方法:将数组转换成list集合。

    String[] arr = {"abc","kk","qq"};
    List<String> list = Arrays.asList(arr);// 将arr数组转成list集合。
    

    二、集合:

    1、集合和数组的区别:

    • 数组是固定长度的;集合可变长度的。
    • 数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
    • 数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
    image.png

    2、Set集合:
    无序(存入和取出顺序有可能不一致),不可以存储重复元素,必须保证元素唯一性。它的各个实现的特点如下:

    • HashSet:底层数据结构是哈希表,线程是不同步的。无序,高效;HashSet集合通过元素的hashCode方法和equals方法保证元素的唯一性。当元素的hashCode值相同时,才继续判断元素的equals是否为true。如果为true,那么视为相同元素,不存。如果为false,那么存储。如果hashCode值不同,那么不判断equals,从而提高对象比较的速度。
    • LinkedHashSet:有序,hashset的子类。
    • TreeSet:对Set集合中的元素的进行指定顺序的排序,排序需要依据元素自身具备的比较性,如果元素不具备比较性,在运行时会发生ClassCastException异常。线程不同步。TreeSet底层的数据结构就是二叉树。

    3、List集合:
    有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。它的实现有三个:

    • ArrayList:底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快。
    • LinkedList:底层的数据结构是链表,线程不同步,增删元素的速度非常快。
    • Vector:底层的数据结构就是数组,线程同步的,Vector无论查询和增删都巨慢。

    4、Map集合:
    以键值对形式存储元素,其各个实现的特点如下:

    • Hashtable:底层是哈希表数据结构,是线程同步的。不可以存储null键,null值。
    • HashMap:底层是哈希表数据结构,是线程不同步的。可以存储null键,null值。替代了Hashtable。
    • TreeMap:底层是二叉树结构,可以对map集合中的键进行指定顺序的排序。

    5、集合使用技巧:

    • 看到Array就是数组结构,有角标,查询速度很快。
    • 看到link就是链表结构:增删速度快,而且有特有方法:addFirst()、 addLast()、 removeFirst()、 removeLast()、 getFirst()、getLast();
    • 看到hash就是哈希表,就要想到哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖hashCode和equals方法。
    • 看到tree就是二叉树,就要想到排序,就要用到比较。
    • 如何判断使用哪个集合?存储一个元素且要保证唯一性就用Set,存储一个元素不用保证唯一性就用List,存储含有映射关系的对象就用Map。

    三、IO流:

    IO流就是用来处理设备上的数据的,输入和输出是以内存为参照物。InputStream,输入流,把计算机的数据输入到内存,所以是读;OutputStream,输出流,把内存中的数据输出到计算机,所以是写。
    1、IO流分类:

    • 字节流(InputStream 和 OutputStream):处理字节数据的流对象。设备上的数据无论是图片、视频还是文字,它们都以二进制存储的。计算机中的最小数据单元就是字节,这就意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。
    • 字符流(Reader 和 Writer):因为每个国家的字符都不一样,所以涉及到了字符编码问题。GBK编码的中文用unicode编码解析是有问题的,所以需要获取中文字节数据的同时再指定的编码表才可以解析正确数据。为了方便于文字的解析,所以将字节流和编码表封装成对象,这个对象就是字符流。只要操作字符数据,优先考虑使用字符流体系。

    2、IO流继承体系:
    (1).字节流:
    InputStream:是表示字节输入流的所有类的超类。

    • |--- FileInputStream:从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符,请考虑使用 FileReader。
    • |--- FilterInputStream:包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。
            |--- BufferedInputStream:该类实现缓冲的输入流。
            |--- Stream
    • |--- ObjectInputStream:
    • |--- PipedInputStream:

    OutputStream:此抽象类是表示输出字节流的所有类的超类。

    • |--- FileOutputStream:文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。
    • |--- FilterOutputStream:此类是过滤输出流的所有类的超类。
            |--- BufferedOutputStream:该类实现缓冲的输出流。
            |--- PrintStream
            |--- DataOutputStream
    • |--- ObjectOutputStream
    • |--- PipedOutputStream

    (2).字符流:
    Reader:用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。

    • |--- BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
            |---LineNumberReader:跟踪行号的缓冲字符输入流。此类定义了 setLineNumber(int)方法 和 getLineNumber()方法,它们可分别用于设置和获取当前行号。
    • |--- InputStreamReader:称为转换流,是字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
            |--- FileReader:InputStreamReader的子类,最常用的转换流。用来读取字符文件的便捷类。
    • |--- CharArrayReader
    • |---StringReader

    Writer:写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。

    • |--- BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
    • |--- OutputStreamWriter:称为转换流,是字符流通向字节流的桥梁:可使用指定的charset将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
            |--- FileWriter:OutputStreamWriter的子类,最常用的转换流。用来写入字符文件的便捷类。
    • |--- PrintWriter
    • |--- CharArrayWriter
    • |--- StringWriter

    下面介绍几个流的用法,看下面例子:

      /*创建可以读取文本文件的流对象,FileReader让创建好的流对象和指定的文件相关联。*/
      FileReader fr = new FileReader("demo.txt");
      int ch = 0;
      while((ch = fr.read())!= -1) { //条件是没有读到结尾
          System.out.println((char)ch); //调用读取流的read方法,读取一个字符。
      }
      fr.close();
      /* =======================下面这种自定义缓冲区的方式更高效=============================== */
      FileReader fr = new FileReader("demo.txt"); //创建读取流对象和指定文件关联。
      //因为要使用read(char[])方法,将读取到字符存入数组。
      //所以要创建一个字符数组,一般数组的长度都是1024的整数倍。
      char[] buf = new char[1024];
      int len = 0;
      while(( len=fr.read(buf)) != -1) {
             System.out.println(new String(buf,0,len));
      }
      fr.close();
      /* ==================================== 高效写数据 ======================================*/
      FileWriter fw = new FileWriter("bufdemo.txt");
      BufferedWriter bufw = new BufferedWriter(fw);//让缓冲区和指定流相关联。
      for(int x=0; x<4; x++){
        bufw.write(x+"abc");
        bufw.newLine(); //写入一个换行符,这个换行符可以依据平台的不同写入不同的换行符。
        bufw.flush();//对缓冲区进行刷新,可以让数据到目的地中。
      }
      bufw.close();//关闭缓冲区,其实就是在关闭具体的流。
      /* ==================================== 高效读数据 ======================================*/
      FileReader fr = new FileReader("bufdemo.txt");
        BufferedReader bufr  = new BufferedReader(fr);
        String line = null;
        while((line=bufr.readLine())!=null){  //readLine方法返回的时候是不带换行符的。
            System.out.println(line);
        }
      bufr.close();
    

    3、流的操作规律:
    从上面的流体系可以看到,Java提供了很多的流供我们使用,感觉很复杂。那么使用的时候该如何选择呢?就得明确以下几点:
    (1). 明确目的:

    • 读数据:使用InputStream、Reader体系
    • 写数据:使用OutputStream、Writer体系

    (2). 操作的数据是否是纯文本数据?

    • 如果是:读数据:Reader;写数据:Writer
    • 若不是:读数据:InputStream;写数据:OutputStream

    (3). 虽然确定了一个体系,但是该体系中有太多的对象,到底用哪个呢?

    • 从何处读取数据:硬盘(File),内存(流),键盘(System.in)
    • 把数据写到何处:硬盘(File),内存(流),控制台(System.out)

    (4). 需要在基本操作上附加其他功能吗?比如缓冲。如果需要就进行装饰,那就用带Buffer的流。

    (5). 凡是操作设备上的文本数据,涉及编码转换,必须使用转换流。

    4、File类:
    将文件系统中的文件和文件夹封装成了对象。提供了更多的属性和行为可以对这些文件和文件夹进行操作。这些是流对象办不到的,因为流只操作数据。常用方法如下:
    (1). 创建:

    boolean createNewFile(); //在指定目录下创建文件,如果该文件已存在,则不创建。
    boolean mkdir(); //创建此抽象路径名指定的目录。
    boolean mkdirs(); //创建多级目录。
    

    (2). 删除:

    boolean delete(); //删除此抽象路径名表示的文件或目录。
    void deleteOnExit(); //在虚拟机退出时删除。
    // 注意:在删除文件夹时,必须保证这个文件夹中没有任何内容,才可以将该文件夹用delete删除。
    // java删除文件不走回收站。要慎用。
    

    (3). 获取:

    long length(); //获取文件大小。
    String getName(); //返回由此抽象路径名表示的文件或目录的名称。
    String getPath(); //将此抽象路径名转换为一个路径名字符串。
    String getAbsolutePath(); //返回此抽象路径名的绝对路径名字符串。
    String getParent(); //返回此抽象路径名父目录的抽象路径名,如果此路径名没有指定父目录,则返回 null。
    long lastModified(); //返回此抽象路径名表示的文件最后一次被修改的时间。
    File.pathSeparator; //返回当前系统默认的路径分隔符,windows默认为 “;”。
    File.Separator; //返回当前系统默认的目录分隔符,windows默认为 “\”。
    

    (4). 判断:

    boolean exists();// 判断文件或者文件夹是否存在。
    boolean isDirectory(); //测试此抽象路径名表示的文件是否是一个目录。
    boolean isFile(); //测试此抽象路径名表示的文件是否是一个标准文件。
    boolean isHidden(); //测试此抽象路径名指定的文件是否是一个隐藏文件。
    boolean isAbsolute(); //测试此抽象路径名是否为绝对路径名。
    

    (5). 重命名:

     boolean renameTo(File dest); //可以实现移动的效果。剪切+重命名。
    

    (6). String[] list():列出指定目录下的当前的文件和文件夹的名称。包含隐藏文件。
    如果调用list方法的File 对象中封装的是一个文件,那么list方法返回数组为null。如果封装的对象不存在也会返回null。只有封装的对象存在并且是文件夹时,这个方法才有效。

    四、网络编程:

    所谓网络编程,其实可以简单的理解为就是在两个或两个以上的设备之间传输数据。
    1、相关概念:

    • IP:为了能够识别接入互联网的每个设备,网络中的每个设备都会有一个唯一的数字标识,这个标识就是IP。就像手机号用来标识不同的手机用户一样。每个计算机在联网后都有一个唯一的合法IP地址。
    • 域名:由于IP地址是一串数字不方便记忆,所以为了方便记忆就有了域名这个概念。就像手机号码不方便记忆,你会设置备注一样。一个IP地址可以对应多个域名,一个域名只能对应一个IP。
    • DNS服务器:上面说了,IP是联网计算机的唯一标识,但是使用的时候我们又会用域名代替IP,所以在实际传输数据前需要将域名转换为IP地址。实现将域名解析为IP地址的服务器就叫DNS服务器。所以我们在地址栏请求某个域名时,首先请求的是DNS服务器。
    • 端口:IP和域名就能很方便的在网络中找到该IP对应的计算机,但是一个计算机可以同时运行多个网络程序,为了区分每个程序,就引入了端口这个概念。IP是区分不同的计算机的,端口就是区分同一台电脑上不同的应用程序的。有效端口:0 ~ 65535,其中0 ~1024系统使用或保留端口。

    有了IP + 端口,就可以标识唯一的一台计算机上的一个唯一的程序了。但是网络程序之间还需要进行数据交换,所以还需要了解网络通讯。

    • 网络通讯:可以理解为就是不同计算机之间进行数据交换。网络通讯基于“请求-响应”模型。所谓的“请求-响应”模型,就是一问一答都形式,一端请求,另一端就响应,不请求就不会有响应。
    • 客户端(client):在网络通讯中,主动发起通讯的程序被称作客户端程序,简称客户端。
    • 服务器(server):而在一次网络通讯中等待连接的程序叫做服务器端程序,简称服务器。

    这样的网络编程结构被称作客户端/服务器结构,简称C/S结构。这种结构的程序通用性差,一个程序的客户端只能和与之对应的服务器通讯,而不能和其他服务器通讯。我们还有另一种方式,就是使用浏览器作为通用客户端与服务器进行通讯,这种使用浏览器作为客户端的结构称作浏览器/服务器结构,简称B/S结构

    • 协议:这是网络编程中最重要也是最复杂的一个概念。网络编程就是运行在不同计算机中的两个程序之间的数据交互。但是计算机毕竟不是人脑,接收到的数据它也无法理解。为了让计算机能理解接收的数据,就需要规定该数据的格式,这个数据的格式就叫做协议。就比如发送电报,先按照某种规则加密,另一端接收到的是加密后的电报,想要知道电报内容,就得按照规则解密,这种规则就叫协议。协议格式是随便编写的,只要按照这种格式能生成唯一的编码,另一端能唯一的解析出数据的内容即可。也正是这个原因,导致客户端只能和与之对应的服务器通讯。
    • 网络通讯方式:TCP和UDP方式。TCP方式建立专门的虚拟连接,进行可靠的数据传输,所以重要的数据一般采用这种方式传输;而UDP方式不需要建立虚拟连接,数据传输不可靠。

    2、 网络编程步骤:
    (1). 客户端网络编程步骤:

    • 建立网络连接
    • 交换数据
    • 关闭网络连接

    (2). 服务端网络编程步骤:

    • 监听端口
    • 获得连接
    • 交换数据
    • 关闭连接

    3、Java网络编程:
    和网络编程相关的API位于java.net包下。
    (1). 部分相关API如下:

    • InetAddress:java 中ip对象
    • Socket:套接字,通信的端点。就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输。
    • DatagramPacket:通过这个对象中的方法,就可以获取到数据包中的各种信息。
    • DatagramSocket.:封装了udp传输协议的socket对象。

    (2). UDP方式案例:
    客户端:

    public static void main(String[] args)throws Exception {
            //1,建立udp的socket服务。
            DatagramSocket ds = new DatagramSocket(8888);//指定发送端口,不指定系统会随机分配。
            //2,明确要发送的具体数据。
            String text = "演示udp传输";
            byte[] buf = text.getBytes();
            //3,将数据封装成了数据包。
            DatagramPacket dp = new DatagramPacket(buf,
                                     buf.length,InetAddress.getByName("10.1.31.127"),10000);
            //4,用socket服务的send方法将数据包发送出去。
            ds.send(dp);
            //5,关闭资源。
            ds.close();
        }
    

    服务端:

    public static void main(String[] args) throws Exception{
            //1,创建udp的socket服务。
            DatagramSocket ds = new DatagramSocket(10000);
            //2,定义数据包,用于存储接收到数据。先定义字节数组,数据包会把数据存储到字节数组中。
            byte[] buf = new byte[1024];
            DatagramPacket dp = new DatagramPacket(buf,buf.length);
            // 3,通过socket服务的接收方法将收到的数据存储到数据包中。
            ds.receive(dp);//该方法是阻塞式方法。
            // 4,通过数据包的方法获取数据包中的具体数据内容,比如ip,端口,数据等等。
            String ip = dp.getAddress().getHostAddress();
            int port = dp.getPort();
            String text = new String(dp.getData(),0,dp.getLength());//将字节数组中的有效部分转成字符串。
            System.out.println(ip+":"+port+"--"+text);
            // 5,关闭资源。
            ds.close();
        }
    

    (3). TCP方式案例:
    客户端:

    public static void main(String[] args) throws Exception{
            Socket s = new Socket("10.1.31.69",10002);
            OutputStream out = s.getOutputStream();//获取了socket流中的输出流对象。
            out.write("tcp演示".getBytes());
            s.close();
    }
    

    服务端:

    public static void main(String[] args) throws Exception{
            ServerSocket ss = new ServerSocket(10002);//建立服务端的socket服务
            Socket s = ss.accept();//获取客户端对象
            String ip = s.getInetAddress().getHostAddress();
            System.out.println(ip+".....connected");
            //可以通过获取到的socket对象中的socket流和具体的客户端进行通讯。
            InputStream in = s.getInputStream();//读取客户端的数据,使用客户端对象的socket读取流
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            String text = new String(buf,0,len);
            System.out.println(text);
            //如果通讯结束,关闭资源。注意:要先关客户端,在关服务端。
            s.close();
            ss.close();
        }
    

    五、设计模式:

    Java有23中设计模式,这里只挑几个常用的说一说,想深入了解可以研读《Java设计模式》这本书。
    1、单例模式:
    什么叫单例,就是保证一个类在内存中只有一个对象。Runtime()方法就是单例设计模式进行设计的。
    (1). 保证对象唯一的思路:

    • 不让其他程序创建该类对象。
    • 在本类中创建一个本类对象。
    • 对外提供方法,让其他程序获取这个对象。

    (2). 实现步骤:

    • 私有化构造函数;
    • 创建私有并静态的本类对象;
    • 定义公有并静态的方法,返回该对象。

    (3). 代码实现:

    • 懒汉式:延迟加载
    class Single{
        private Single(){} // 将构造方法私有化
        private static Single s = null; // 私有静态的本类对象
        public static synchronized Single getInstance(){ // 静态公共的返回对象的方法
            if(s==null)
                s = new Single();
            return s;
        }
    }
    
    • 饿汉式:
    class Single{
        private Single(){} //私有化构造函数。
        private static Single s = new Single(); //创建私有并静态的本类对象。
        public static Single getInstance(){ //定义公有并静态的方法,返回该对象。
            return s;
        }
    }
    

    2、模板方法模式:
    定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。简单的说就是很多相同的步骤,只是在某一些地方有差别,那么就可以使用这种模式。

    • 获取一段程序运行时间的模板:
    public abstract class GetTime{
          public long getTime(){
             long  start = System.currentTimeMillis;
             //表示要计算运行时间的代码
             code();
             long  end = System.currentTimeMillis;
             return end-start;
          }
          public abstract void code(); 
    }
    
    • 使用该模板:
    public class forDemo extends GetTime{
         //重写抽象方法
         public void code(){
              for(int x=0;x<1000;x++){
                     System.out.println(x);
              }
         }
    }
    
    • 测试:
    public class test{
         GetTime gt=new forDemo();
         gt.getTime();
    }
    

    这样就可以计算那个for循环运行的时间了。

    总结:

    《java基础知识01》和本文简陋的总结了一些java基础的知识点,由于本人只是个小白,只能在此抛砖引玉,望各位大神多多指点!

    相关文章

      网友评论

        本文标题:java基础知识02

        本文链接:https://www.haomeiwen.com/subject/fztmtqtx.html