美文网首页
Java初级笔记No.4(更新中)

Java初级笔记No.4(更新中)

作者: wenmingxing | 来源:发表于2018-07-27 17:03 被阅读17次
    2018.7.27

    1、Java的主要内置数据结构包括:枚举(Enumeration),位集合(BitSet),向量(Vector), 栈(Stack), 字典(Dictionary), 哈希表(Hashtable), 属性(Properties)

    枚举(Enumeration)
    枚举接口定义了一种从数据结构中取回连续元素的方式。例如,枚举定义了一个叫nextElement的方法,该方法用来得到一个包含多个元素的数据结构的下一个元素,在这一点上很像是C++中的迭代器。

    而事实上,这种传统接口确实已经被迭代器取代了,在现在代码中已经很少被使用了。

    import java.util.Vector;
    import java.util.Enumeration;
    
    public class EnumerationTester {
        public static void main(String[] args) {
            Enumeration<String> days;
            Vector<String> dayNames = new Vector<String>();
            dayNames.add("Sunday");
            dayNames.add("Monday");
            dayNames.add("Tuesday");
            dayNames.add("Wednesday");
            dayNames.add("Thursday");
            dayNames.add("Friday");
            dayNames.add("Saturday");
            
            days = dayNames.elements();
            while (days.hasMoreElements()) {
                System.out.println(days.nextElement());
            }
        }
    }
    

    位集合(BitSet)
    位集合实现了一组可以单独设置和清除的位或标志。
    该类在处理一组Boolean值的时候非常有用,只需要给每个值赋予一位,然后对位进行相应的设置或清除,就可以对布尔值进行操作了。

    import java.util.BitSet;
    
    public class BitSetDemo {
        public static void main(String[] args) {
            BitSet bits1 = new BitSet(16);
            BitSet bits2 = new BitSet(16);
            
            // set some bits
            for (int i = 0; i < 16; ++i) {
                if (i % 2 == 0) bits1.set(i);
                if (i % 5 != 0) bits2.set(i);
            }
            
            System.out.println("Initial pattern in bits1 : ");
            System.out.println(bits1);
            
            System.out.println("Initial pattern in bits2 : ");
            System.out.println(bits2);
            
            // AND bits
            bits2.and(bits1);
            System.out.println("bits2 AND bits1 : ");
            System.out.println(bits2);  
            
            // OR bits
            bits2.or(bits1);
            System.out.println("bits2 OR bits1 : ");
            System.out.println(bits2);
            
            // XOR bits
            bits2.xor(bits1);
            System.out.println("bits2 XOR bits1 : ");
            System.out.println(bits2);
        }
    }
    

    向量(Vector)
    向量类和传统数组非常类似,但是Vector的大小能根据需要动态的变化。
    与C++STL中的vector中不同,Java的Vector中可以存储不同类型的元素:

    import java.util.*;
    
    public class VectorDemo {
        public static void main(String[] args) {
            Vector v = new Vector(3,2);
            System.out.println("Initial size : " + v.size());
            System.out.println("Initial capacity : " + v.capacity());
            
            v.addElement(new Integer(1));
            v.add(2);
            v.add(3);
            v.add(4);
            
            System.out.println("Capacity after four additions:" + v.capacity());
            
            v.addElement(new Double(5.45));
                    v.addElement(new String("haha"));
            
            Enumeration vEnum = v.elements();
            System.out.println("Elements in vector:");
            while (vEnum.hasMoreElements()) {
                System.out.println(vEnum.nextElement() + " ");
            }
            System.out.println();
        }
    }
    

    栈(Stack)

    package test3;
    
    import java.util.*;
    
    public class StackDemo {
        static void showpush(Stack<Integer> st, int a) {
            st.push(new Integer(a));
            System.out.println("push(" + a + ")");
            System.out.println("stack: " + st);
        }
        
        static void showpop(Stack<Integer> st) {
            System.out.print("pop -> ");
            Integer a = (Integer) st.pop();
            System.out.println(a);
            System.out.println("stack : " + a);
        }
        
        public static void main(String[] args) {
            Stack<Integer> st = new Stack<Integer>();
            
            System.out.println("stack : " + st);
            showpush(st, 42);
            showpush(st, 66);
            showpush(st, 99);
            
            showpop(st);
            showpop(st);
            showpop(st);
            
            try {
                showpop(st);
            } catch (EmptyStackException e) {
                System.out.println("empty stack");
            }
        }
    }
    

    字典(Dictionary)
    字典类定义了键映射到值的数据结构。
    其实Dictionary已经过时了,在实际开发中应该使用Map接口来实现k-v的存储功能。

    package test3;
    
    import java.util.*;
    
    public class MapDemo {
        public static void main(String[] args) {
            Map m1 = new HashMap();
            m1.put("Zara", "8");
            m1.put("Mahnaz", "31");
            m1.put("Ayan", "12");
            m1.put("Daisy", "14");
            
            System.out.println();
            System.out.println("Map Elements");
            
            System.out.println(m1);
            
            System.out.println(m1.get("Zara"));
        }
    }
    
    

    哈希表(Hashtable)
    Hashtable类提供了一种在用户定义键结构的基础上来组织数据的手段。
    例如,在地址列表的哈希表中,你可以根据邮政编码作为键来存储和排序数据,而不是通过人名。

    其实Hashtable就是Dictionary的具体实现,与HashMap类很相似,但是其支持同步。

    package test3;
    
    import java.util.*;
    
    public class HashTableDemo {
        public static void main(String[] args) {
            //Create a hash
            Hashtable balance = new Hashtable();
            Enumeration names;
            String str;
            double bal;
            
            balance.put("Zara", new Double(3434.34));
            balance.put("Mahnaz", new Double(123.22));
            balance.put("Ayan", new Double(1378.00));
            balance.put("Daisy", new Double(99.22));
            balance.put("Qadir", new Double(-19.08));
            
            // Show all balances in hash table
            names = balance.keys();
            while (names.hasMoreElements()) {
                str = (String) names.nextElement();
                System.out.println(str + ": " + balance.get(str));
            }
            
            System.out.println();
            
            //Deposit 1000 into Zara's account
            bal = ((Double)balance.get("Zara")).doubleValue();
            balance.put("Zara", new Double(bal+1000));
            System.out.println("Zara's new balance:" + balance.get("Zara"));
        }
    }
    

    属性(Properties)
    Properties继承于Hashtable。表示一个持久的属性集。属性列表中每个键及其对应值都是一个字符串。

    import java.util.*;
     
    public class PropDemo {
     
       public static void main(String args[]) {
          Properties capitals = new Properties();
          Set states;
          String str;
          
          capitals.put("Illinois", "Springfield");
          capitals.put("Missouri", "Jefferson City");
          capitals.put("Washington", "Olympia");
          capitals.put("California", "Sacramento");
          capitals.put("Indiana", "Indianapolis");
     
          // Show all states and capitals in hashtable.
          states = capitals.keySet(); // get set-view of keys
          Iterator itr = states.iterator();
          while(itr.hasNext()) {
             str = (String) itr.next();
             System.out.println("The capital of " +
                str + " is " + capitals.getProperty(str) + ".");
          }
          System.out.println();
     
          // look for state not in list -- specify default
          str = capitals.getProperty("Florida", "Not Found");
          System.out.println("The capital of Florida is "
              + str + ".");
       }
    }  
    

    2、Java集合框架

    集合框架被设计成要满足以下几个目标:
    · 该框架必须是搞性能的,基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的;
    · 该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性;
    · 对一个集合的扩展和适应必须是简单的。

    集合框架是一个用来代表和操纵集合的同一架构。所有的集合框架都包含如下内容:
    · 接口:代表集合的首先数据类型。例如Collection、List、Set、Map等。之所以定义多个接口,是为了以不同方式操作集合对象;
    · 实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,如ArrayList、LinkedList、HashSet、HashMap;
    · 算法: 是实现集合接口的对象里的方法执行的一些有用的算法, 如搜索和排序,这些算法被称为多态,那是因为相同的方法可以在相似的接口上有不同的实现。

    3、使用迭代器
    迭代器,能够通过血环来得到或删除集合的元素。如ListIterator继承了Iterator,以允许双向遍历列表和修改元素。

    遍历ArrayList

    package test3;
    
    import java.util.*;
    public class Test {
        public static void main(String[] args) {
            List<String> list = new ArrayList<String>();
            list.add("Hello");
            list.add("World");
            list.add("HAHAHAHA");
            
            // 第一种遍历方法,使用foreach遍历List
            for (String str : list) {
                System.out.println(str);
            }
            
            //第二种遍历方式,将链表变为数组相关的内容
            String[] strArray = new String[list.size()];
            list.toArray(strArray);
            for (int i = 0; i < strArray.length; ++i) {
                System.out.println(strArray[i]);
            }
            
            //第三种遍历方式,使用Iterator
            Iterator<String> ite = list.iterator();
            while (ite.hasNext()) {
                System.out.println(ite.next());
            }
            
        }
    }
    

    遍历Map

    package test3;
    
    import java.util.*;
    public class Test {
        public static void main(String[] args) {
            Map<String, String> map = new HashMap<String, String>();
            map.put("1", "value1");
            map.put("2", "value2");
            map.put("3", "value3");
            
            //第一种遍历方法,普遍使用,二次取值
            System.out.println("通过Map.keySet遍历key和value:");
            for (String key : map.keySet()) {
                System.out.println("key = " + key + " and value = " + map.get(key));
            }
            
            //第二种遍历方式
            System.out.println("通过Map.entrySet使用iterator遍历key和value:");
            Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, String> entry = it.next();
                System.out.println("key=" + entry.getKey() + " and value=" + entry.getValue());
            }
            
            //第三种遍历方式,推荐,尤其是在容量大时 
            System.out.println("通过Map.entrySet遍历key和value:");
            for (Map.Entry<String, String> entry : map.entrySet()) {
                System.out.println("key=" + entry.getKey() + " and value=" + entry.getKey());
            }
            
            //第四种遍历方式
            System.out.println("通过Map.values()遍历所有的value,但是不能得到key:");
            for (String v : map.values()) {
                System.out.println("value = " + v);
            }
        }
    }
    

    4、了解Java泛型
    泛型的概念与C++中的泛型没有区别,这是一种程序设计思想。
    泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
    可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

    下面是定义泛型方法的规则:
    · 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前;
    · 每一个类型参数声明部分包含一个或多个类型参数,参数见用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符;
    · 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符;
    · 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用类型,不能是原始类型(如int,double,char等)。

    实例
    下面的例子演示了如何使用泛型方法打印不同字符串的元素:

    public class GenericMethodTest {
        //泛型方法 printArray
        public static <E> void printArray(E[] inputArray) {
            //
            for (E element : inputArray) {
                System.out.printf("%s", element);
            }
            System.out.println();
        }
        
        public static void main(String[] args) {
            Integer[] intArray = {1,2,3,4,5};
            Double[] doubleArray = {1.1,2.2,3.3,4.4,5.5};
            Character[] charArray = {'H', 'E', 'L', 'L', 'O'};
            
            System.out.println("Integer : ");
            printArray(intArray);
            
            System.out.println("Double : ");
            printArray(doubleArray);
            
            System.out.println("Character : ");
            printArray(charArray);
            
        }
    }
    

    有界的参数实例
    有时候,我们会想限制那些被允许传递到一个类型参数的类型种类范围,例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。者就是有界类型参数的目的。
    首先需要列出参数类型的名称,后面跟extends或者implements

    package test2;
    
    public class MaximumTest {
        /*返回三个可被Comparable的最大值*/
        public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
            T max = x;
            if (y.compareTo(max) > 0)
                max = y;
            if (z.compareTo(max) > 0)
                max = z;
            
            return max;
        }
        
        public static void main(String[] args) {
            System.out.printf("%d, %d, %d 中最大的数为:%d\n\n", 3,4,5,maximum(3,4,5));
            
            System.out.printf("%.1f, %.1f, %.1f 中最大的数为:%.1f\n\n", 6.6,8.8,7.7, maximum(6.6,8.8,7.7));
            
            System.out.printf("%s, %s, %s 中最大的数为: %s\n\n", "apple", "pear", "orange", maximum("apple", "pear", "orange"));
        }
    }
    

    5、泛型类

    泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。

    和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数见用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。

    package test2;
    
    public class Box<T> {
        private T t;
        public void add(T t) {
            this.t = t;
        }
        
        public T get() {
            return t;
        }
        
        public static void main(String[] args) {
            Box<Integer> integerBox = new Box<Integer>();
            Box<String> stringBox = new Box<String>();
            
            integerBox.add(new Integer(10));
            stringBox.add(new String("LiMing"));
            
            System.out.println("Integer:" + integerBox.get());
            System.out.println("String:" + stringBox.get());
        }
    }
    
    

    6、类型通配符

    类型通配符一般是使用?代替具体类型参数。例如List<?>在逻辑上是List<String>, List<Integer>, 等所有List<>的父类:

    package test2;
    
    import java.util.*;
    
    public class GenericTest {
        public static void main(String[] args) {
            List<String> name = new ArrayList<String>();
            List<Integer> age = new ArrayList<Integer>();
            List<Number> number = new ArrayList<Number>();
            
            name.add("icon");
            age.add(18);
            number.add(314);
            
            getData(name);
            getData(age);
            getData(number);
        }
        
        public static void getData(List<?> data) {
            System.out.println(data.get(0));
        }
    }
    

    因为getData()这个方法的参数是List<?>类型的,所以name,age,number都可以作为这个方法的实参,这就是通配符的作用。

    同理,也可以限定类型通配符上限,例如令其只能接受Number及其下层子类类型:

    public static void getData(List<? extends Number> data) {
        System.out.println(data.get(0));
    }  
    

    这样的话,对于String类型的name就会报错。

    7、Java序列化

    Java中提过了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括了该对象的数据、有关对象的类型的信息和存储在对象中的数据的类型。

    将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。

    这个过程都是JVM实现的,也就是说,在一个平台上序列化的对象可以在另一个平台上完成反序列化。

    类ObjectInputStream和ObjectOutputStream是高层次的数据流,它们包含反序列化和序列化对象的方法。

    该方法序列化一个对象,并将它发送到输出流。

    public final void writeObject(Object x) throws IOException
    

    readObject()方法可以反序列化一个对象,它的返回值是Object,因此需要将它转化成何时的数据类型:

    public final Object readObject() throws IOException ClassNotFoundException
    

    实例
    一个类的对象要向序列化成功,必须满足两个条件:
    · 该类必须实现java.io.Serializable接口;
    · 该类的所有属性必须是可序列化的。

    public class Employee implements java.io.Serializable {
        public String name;
        public String address;
        public transient int SSN;   //不包含在序列化表示中
        public int number;
        public void mailCheck() {
            System.out.println("Mailing a check to " + name + " " + address);
        }
    }
    

    ObjectOutputStream类用来序列化一个对象,如下的SerializeDemo例子实例化了上面的Employee对象,并将该对象序列化到了一个文件中。

    改程序执行后,会创建一个名为employee.ser文件,当然也可以为.txt文件。

    import java.io.*;
    
    public class SerializeDemo {
        public static void main(String[] args) {
            Employee e = new Employee();
            e.name = "LiMing";
            e.address = "BeiJing";
            e.SSN = 11122333;
            e.number = 101;
            
            try {
                FileOutputStream fileOut = new FileOutputStream("/tmp/employee.ser");
                ObjectOutputStream out = new ObjectOutputStream(fileOut);
                out.writeObject(e);     //序列化
                out.close();
                fileOut.close();
                System.out.println("Serialized data is saved in /tmp/employee.ser");
            } catch(IOException i) {
                i.printStackTrace();
            }
        }
    }  
    

    下面的DeserializeDemo程序实现了反序列化:

    public class DeserializeDemo
    {
       public static void main(String [] args)
       {
          Employee e = null;
          try
          {
             FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             e = (Employee) in.readObject();
             in.close();
             fileIn.close();
          }catch(IOException i)
          {
             i.printStackTrace();
             return;
          }catch(ClassNotFoundException c)
          {
             System.out.println("Employee class not found");
             c.printStackTrace();
             return;
          }
          System.out.println("Deserialized Employee...");
          System.out.println("Name: " + e.name);
          System.out.println("Address: " + e.address);
          System.out.println("SSN: " + e.SSN);
          System.out.println("Number: " + e.number);
        }
    }  
    

    运行结果为:

    由于属性SSN被设置为了transient,表示为短暂的,不会被发送到输出流,也就不会参与序列化,所以反序列化后的SSN属性为0。

    8、Java中的Socket编程
    在java中java.net.Socket代表一个套接字,并且java.net.ServerSocket类为服务器程序提供了一种来监听客户端,并建立连接的机制。

    java中Socket编程的基本步骤如下:
    · 服务器实例化一个ServeSocket对象,表示通过服务器上的端口通信。
    · 服务器调用ServerSocket类的accept方法,该方法将一直等待,知道客户端连接到服务器上给定的端口;
    · 服务器正在等待,一个客户端实例化一个Socket对象,指定服务器名称和端口号来请求连接;
    · Socket类的构造函数视图将客户端连接到指定的服务器和端口。如果通信被简历,则客户端创建一个Socket对象能够与服务器进行通信;
    · 在服务器端,accept()方法返回服务器上一个新的socket引用,该socket连接到客户端的socket;

    连接建立后,通过使用I/O流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接服务器端的输入流,而客户端的输入流连接服务器端的输出流。

    /*client*/
    
    import java.net.*;
    import java.io.*;
    
    public class GreetingClient {
        public static void main(String[] args) {
            String serverName = args[0];
            int port = Integer.parseInt(args[1]);
            try {
                System.out.println("连接到主机:" + serverName + ", 端口号:" + port);
    
                Socket client = new Socket(serverName, port);
                System.out.println("远程主机地址:" + client.getRemoteSocketAddress());
                OutputStream outToServer = client.getOutputStream();
                DataOutputStream out = new DataOutputStream(outToServer);
    
                out.writeUTF("Hello from " + client.getLocalSocketAddress());
                InputStream inFromServer = client.getInputStream();
                DataInputStream in = new DataInputStream(inFromServer);
                System.out.println("服务器响应:" + in.readUTF());
                client.close();
            } catch(IOException e) {
                e.printStackTrace();
            }
        }
    }  
    
    /*server*/
    
    import java.net.*;
    import java.io.*;
    
    public class GreetingServer extends Thread {
        private ServerSocket serverSocket;
    
        public GreetingServer(int port) throws IOException {
            serverSocket = new ServerSocket(port);
            serverSocket.setSoTimeout(10000);
        }
    
        public void run() {
            while (true) {
                try {
                    System.out.println("等待远程连接,端口号为:" + serverSocket.getLocalPort() + "...");
                    Socket server = serverSocket.accept();
                    System.out.println("远程主机地址:" + server.getRemoteSocketAddress());
    
                    DataInputStream in = new DataInputStream(server.getInputStream());
                    System.out.println(in.readUTF());
                    DataOutputStream out = new DataOutputStream(server.getOutputStream());
    
                    out.writeUTF("谢谢连接我:" + server.getLocalSocketAddress() + "Goodbye!");
                    server.close();
    
                } catch(SocketTimeoutException s) {
                    System.out.println("Socket timed out!");
                    break;
                } catch(IOException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    
        public static void main(String[] args) {
            int port = Integer.parseInt(args[0]);
            try {
                Thread t = new GreetingServer(port);
                t.run();
            } catch(IOException e) {
                e.printStackTrace();
            }
        }
    }  
    

    相关文章

      网友评论

          本文标题:Java初级笔记No.4(更新中)

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