JAVA知识梳理

49次阅读

共计 44506 个字符,预计需要花费 112 分钟才能阅读完成。

由于最近一个项目需要, 需要学习 JAVA 知识, 学习的过程中做了一些笔记, 主要以知识点记录为主, 现在分享出来供参考. 大部分内容是参考的自强学堂. 这里做了归纳.
接口:

在 JAVA 中, 接口可理解为对象间相互通信的协议, 接口在继承中扮演着很重要的角色
接口只定义派生要用到的方法, 但方法的具体实现完全取决于派生类

JAVA 面向对象中支持的基本概念:

封装, 继承, 多态, 抽象, 类, 对象, 实例, 方法, 消息解析

类:

是一个模板, 它描述一类对象的行为和状态, 创建 JAVA 对象的模板

对象:

类的一个实例, 有状态和行为

类变量:

声明在类中, 方法体之外, 但必须声明为 static 类型

构造方法:

在创建一个对象的时候, 至少要调用一个构造方法, 构造方法的名称必须与类同名, 一个类可以有多个构造方法

创建对象:

需要三步:1. 声明, 声明一个对象, 包括对象名称和类型
         2. 实例化, 使用关键字 new 来创建一个对象
         3. 初始化, 使用 new 创建对象时, 会调用构造方法初始化对象

public class Puppy{public Puppy(String name){
        // 这个构造器仅有一个参数:name
        System.out.println("Passed Name is :" + name);
    }
    public static void main(String[] args){Puppy myPuppy = new Puppy("zhangtong");
    }
}

源文件声明规则:

一个源文件中只能有一个 public 类
一个源文件可以有多个非 public 类
源文件的名称应该和 public 的类名保持一致.
如果一个类定义在某个包中, 那么 package 语句应该放在源文件的首行
如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面
import 语句和 package 语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明

引用类型

引用类型变量由类的构造函数创建, 可以使用它们访问所引用的对象.
对象、数组都是引用数据类型
所有引用类型的默认值都是 null
一个引用变量可以用来引用与任何与之兼容的类型

常量

是一个固定值, 不需要计算, 直接代表相应的值, 不能改变
final double PI = 3.1415926;
常量名一般大写
字面量可以赋给任何内置类型的变量
byte a = 68;
char a = 'A';

字符串常量和字符常量都可以包括任何 Unicode 字符
char a = '\u0001';
String a = "\u0001";

转义字符

Java 支持一些特殊的转义字符序列
\n 换行
\r 回车
\f 换页符
\b 退格
\s 空格
\t 制表符
\" 双引号
\' 单引号
\\ 反斜杠
\ddd 八进制字符
\uxxx 16 进制 unicode 字符

Java 支持的变量类型

局部变量, 成员变量, 类变量(静态变量)

局部变量声明在方法, 构造方法或者语句块中
局部变量在方法, 构造方法, 或者语句块被执行的时候创建, 当它们执行完成后, 变量将会被销毁
访问修饰符不能用于局部变量
局部变量只能在声明它的方法, 构造方法或者语句块中可见
局部变量在栈上分配
局部变量没有默认值, 所以局部变量被声明后, 必须经过初始化才可使用

实例变量声明在一个类中, 但在方法, 构造方法和语句块之外
当一个对象被实例化之后, 每个实例变量的值就跟着确定
实例变量在对象创建的时候创建, 在对象销毁的时候销毁
实例变量的值应该至少被一个方法, 构造方法或者语句块引用, 使得外部能够通过这些方式获取实例变量的信息
访问修饰符可以修饰实例变量
实例变量对于类中的方法, 构造方法或者语句块是可见的, 一般情况下应该把实例变量设为私有.
实例变量具有默认值, 数值类型的默认值是 0, 布尔变量的默认值是 false, 引用类型变量的默认值是 null.

类变量以 static 关键字声明, 但必须在构造方法和语句块之外.
无论一个类创建了多少个对象, 类只拥有类变量的一份拷贝
静态变量除了被声明为常量外很少使用, 常量是指声明为 public/private, final 和 static 类型的变量, 常量初始化后不可改变
静态变量存储在静态存储区, 经常被声明为常量
静态变量在程序开始时创建, 在程序结束时销毁
与实例变量具有相似的可见性, 但为了对类的使用者可见, 大多数静态变量声明为 public
静态变量可通过: ClassName.VariableName 的方式访问
类变量被声明为 public static final 类型时, 类变量名称必须使用大写字母.
如果静态变量不是 public 和 final 类型, 其命名方式与实例变量以及局部变量的命名方式一致

访问控制修饰符

默认的,default, 在同一包内可见, 不使用任何修饰符
私有的, 以 private 修饰符指定, 在同一类内可见
共有的, 以 public 修饰符指定, 对所有的类可见
受保护的, 以 protected 修饰符指定, 对 同一包内的类和所有子类 可见

接口里的变量都隐式声明为 public static final, 而接口里的方法默认情况下访问权限是 public
类和接口不能被声明为 private

private 访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据
如果几个相互访问的 public 类分布在不同的包中, 则需要导入相应 public 类所在的包,
由于类的继承性, 类所有的公有方法和变量都能被其子类继承

接口的成员变量和方法不能声明为 protected

非访问修饰符

static 修饰符, 用来创建方法和类变量
final 修饰符, 用来修饰类, 方法和变量,final 修饰的类不能被继承, 修饰的方法不能被继承类重新定义,
修饰的变量为常量, 是不可修改的.
abstract 修饰符, 用来创建抽象类和抽象方法
synchronized 和 volatile 修饰符, 主要用于线程的编程

static 修饰符:
    静态变量:
        static 关键字用来声明独立于对象的静态变量, 无论一个类实例化多少对象, 它的静态变量只有
        一份拷贝. 静态变量也被称为类变量.
    静态方法:static 关键字用来声明独立于对象的静态方法, 静态方法不能使用类的非静态变量.
    对类变量和方法的访问可以直接使用 classname.variablename 和 classname.methodname 的方式访问.
    
final 修饰符:
    final 变量能被显式地初始化且只能初始化一次, 被声明为 final 的对象的引用不能指向不同的对象.
    但是 final 对象里的数据可以被改变. 也就是说 final 对象的引用不能改变, 但是里面的值可以改变
    
    final 修饰符通常和 static 修饰符一起使用来创建类常量
    
    类中的 final 方法可以被子类继承, 但是不能被子类修改
    声明 final 方法 的主要目的 是防止该方法的内容被修改.
    
    
abstract 修饰符
    抽象类:
        不能用来实例化对象, 声明抽象类的 唯一 目的是为了将来对该类进行扩充
        一个类不能同时被 abstract 和 final 修饰. 如果一个类包含抽象方法, 那么该类一定要声明为抽象类
        抽象类可以包含抽象方法和非抽象方法
    抽象方法:
        抽象方法是一种没有任何实现的方法, 该方法的具体实现由子类提供. 抽象方法不能同时被声明为 final 和 static
        任何继承抽象类的子类必须实现父类的所有抽象方法, 除非该子类也是抽象类
        
synchronized 修饰符
    synchronized 关键字声明的方法同一时间只能被一个线程访问.
    synchronized 修饰符可以应用于四个访问修饰符.

transient 修饰符
    序列化的对象包好被 transient 修饰的实例变量时,java 虚拟机跳过该特定的变量
    该修饰符包含在定义变量的语句中, 用来预处理类和变量的数据类型
    一般变量被 transient 修饰, 变量将不再是对象持久化的一部分, 该变量内容在序列化后无法获得访问
    
volatile 修饰符
    volatile 修饰的成员变量在每次被线程访问时, 都强迫从共享内存中重读该成员变量的值.
    当成员变量发生变化时, 强迫线程将变化值回写到共享内存. 这样在任何时刻, 两个不同的线程总是看到某个成员变量的同一个值.

运算符

算数运算符, 关系运算符, 位运算符, 逻辑运算符, 赋值运算符, 其它运算符
条件运算符(?:), 也称为三元运算符
variable x = (expression) ? value if true : value if false
instanceOf 运算符: 该运算符用于操作对象实例, 检查该对象是否是一个特定类型(类类型或接口类型)

Java Number 类

当需要使用数字的时候, 我们通常使用内置数据类型, 如: byte,int,long,double 等
然鹅, 在实际开发中, 我们经常会遇到需要使用对象, 而不是内置数据类型的情形,
为了解决这个问题,Java 语言为每一个内置数据类型提供了对应的包装类
所有的包装类 (Integer、Long、Byte、Double、Float、Short) 都是抽象类 Number 的子类
这种由 编译器 特别支持的包装称为 装箱, 所以当内置数据类型被当作对象使用的时候,
编译器会把内置类型装箱为包装类. 相似的, 编译器也可把一个对象拆箱为内置类型.
Number 类属于 java.lang 包

Number 类的成员方法
    xxxValue(): 将 number 对象转换为 xxx 数据类型的值并返回
    compareTo(): 将 number 对象与参数比较
    equals(): 判断 number 对象是否与参数相等
    valueOf(): 返回一个 Integer 对象指定的内置数据类型
    toString(): 以字符串形式返回值
    parseInt(): 将字符串解析为 int 类型
    abs(): 返回参数的绝对值
    ceil(): 对整形变量向左取整,返回类型为 double 型
    floor(): 对整型变量向右取整。返回类型为 double 类型
    rint(): 返回与参数最接近的整数。返回类型为 double
    round(): 返回一个最接近的 int、long 型值
    min(): 返回两个参数中的最小值
    max(): 返回两个参数中的最大值
    exp(): 返回自然数底数 e 的参数次方
    log(): 返回参数的自然数底数的对数值
    pow(): 返回第一个参数的第二个参数次方
    sqrt(): 求参数的算术平方根
    sin(): 求指定 double 类型参数的正弦值
    cos(): 求指定 double 类型参数的余弦值
    tan(): 求指定 double 类型参数的正切值
    random(): 返回一个随机数
    

Java Character 类

    使用字符时, 我们通常使用的是内置数据类型 cahr
    然后在实际开发中, 我们经常会遇到需要使用对象, 为了解决这个问题,Java 语言为内置数据
    类型 char 提供了包装类 Character 类.
    
    Character 类提供了一系列方法来操纵字符, 可以使用 Character 的构造方法创建一个 Character 类对象
    Character ch = new Character('a');
    
Character 类的成员方法
    isLetter(): 是否是一个字母
    isDigit(): 是否是一个数字字符
    isWhitespace(): 是否一个空格
    isUpperCase(): 是否是大写字母
    isLowerCase(): 是否是小写字母
    toUpperCase(): 指定字母的大写形式
    toLowerCase(): 指定字母的小写形式
    toString(): 返回字符的字符串形式,字符串的长度仅为 1
    ... 请参考 java.lang.Character API 规范
    

Java String 类

在 Java 中字符串属于对象, Java 提供了 String 类来创建和操作字符串
创建字符串:
    String 类有 11 种构造方法, 这些方法提供不同的参数来初始化字符串
    
    public class Main {public static void main(String[] args) {
        String greeting = "Hello world!";
        char[] helloArray = {'h', 'e', 'l', 'l', 'o', '.'};
        String helloString = new String(helloArray);
        System.out.println(helloString);
    }
}
注意: String 类是不可改变的, 所以一旦创建了 String 对象, 那它的值就无法改变了.
    如果需要对字符串做很多修改, 那么应该选择使用 StringBuffer & StringBuilder 类
    
字符串长度
    用于获取有关对象的信息的方法称为访问器方法
    String 类的一个访问器方法是 length()方法, 它返回字符串对象包含的字符数
连接字符串
    String 类提供了连接两个字符串的方法
        String s3 = string1.concat(string2);    // 返回 string1 连接 string2 的新字符串
        也可对字符串常量使用 concat()方法:
        String s4 = "My name is".concat("Zara");
        
        更常用的是使用 '+' 操作符来连接字符串
        String s5 = "Hello," + "world" + "!";

创建格式化字符串
    String 类使用静态方法 format()返回一个 String 对象而不是 PrintStream 对象
    String 类的静态方法 format()能用来创建可复用的格式化字符串, 而不仅仅是用于一次打印输出
    // 例子:
    String fs;
    float floatVar = 9.8f;
    int intVar = 125;
    String stringVar = "Jimy";
    fs = String.format("The value of the float variable is" +
                        "%f, while the value of the integer" +
                        "variable is %d, and the string" +
                        "is %s", floatVar, intVar, stringVar);
    System.out.println(fs); //The value of the float variable is 9.800000, while the value of the integervariable is 125, and the string is Jimy

String 方法
    char charAt(int index): 返回指定索引处的 char 值
    int compareTo(Object o): 把这个字符串和另一个对象比较
    int compareTo(String anotherString): 按字典顺序比较两个字符串
    int compareToIgnoreCase(String str): 按字典顺序比较两个字符串,不考虑大小写
    String concat(String str): 将指定字符串连接到此字符串的结尾
    boolean contentEquals(StringBuffer sb): 当且仅当字符串与指定的 StringButter 有相同顺序的字符时候返回真
    static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String
    boolean endsWith(String suffix): 测试此字符串是否以指定的后缀结束
    boolean equals(Object anObject): 将此字符串与指定的对象比较
    boolean equalsIgnoreCase(String anotherString): 将此 String 与另一个 String 比较,不考虑大小写
    byte[] getBytes(): 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中
    void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):    将字符从此字符串复制到目标字符数组
    int hashCode(): 返回此字符串的哈希码
    int indexOf(int ch): 返回指定字符在此字符串中第一次出现处的索引
    int lastIndexOf(int ch): 返回指定字符在此字符串中最后一次出现处的索引
    boolean matches(String regex): 告知此字符串是否匹配给定的正则表达式
    boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len):
        测试两个字符串区域是否相等
    String[] split(String regex): 根据给定正则表达式的匹配拆分此字符串
    boolean startsWith(String prefix): 测试此字符串是否以指定的前缀开始
    String substring(int beginIndex): 返回一个新的字符串,它是此字符串的一个子字符串
    char[] toCharArray(): 将此字符串转换为一个新的字符数组
    String toLowerCase(): 使用默认语言环境的规则将此 String 中的所有字符都转换为小写
    String toUpperCase(): 使用默认语言环境的规则将此 String 中的所有字符都转换为大写
    String trim(): 返回字符串的副本,忽略前导空白和尾部空白
    

Java StringBuffer 和 StringBuilder 类

对字符串进行修改的时候, 需要使用 StringBuffer 和 StringBuilder 类
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改, 且不产生新的未使用对象
StringBuffer 和 StringBuilder 类之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)
由于 StringBuilder 相较于 StringBuffer 有速度优势, 大多数情况下建议使用 StringBuilder 类.
然而在应用程序要求线程安全的情况下, 则必须使用 StringBuffer 类
// 例子
public class Main {public static void main(String[] args) {StringBuffer sBuffer = new StringBuffer("test");
        sBuffer.append("String Buffer");
        System.out.println(sBuffer);    //test String Buffer
    }
}

StringBuffer 方法
    public StringBuffer append(String s): 将指定的字符串追加到此字符序列
    public StringBuffer reverse(): 将此字符序列用其反转形式取代
    public delete(int start, int end): 移除此序列的子字符串中的字符
    public insert(int offset, int i): 将 int 参数的字符串表示形式插入此序列中
    replace(int start, int end, String str): 使用给定 String 中的字符替换此序列的子字符串中的字符
    ...

Java 数组

用来存储固定大小的同类型元素
double[] myList;    // 首选的声明写法
myList = new double[1024];    // 创建数组

数组作为函数的参数
    数组可以作为参数传递给方法

数组作为函数的返回值

public class Main {public static void printArray(double[] array){for(int i = 0;i < array.length;i++){System.out.println(array[i] + " ");
        }
    }
    public static double[] reverse(double[] list){double[] result = new double[list.length];
        for(int i = 0, j = result.length - 1; i < list.length; i++, j--){result[j] = list[i];
        }
        return result;
    }
    public static void main(String[] args) {StringBuffer sBuffer = new StringBuffer("test");
        sBuffer.append("String Buffer");
        System.out.println(sBuffer);    //test String Buffer

        double[] myList = {1.9, 2.9, 3.4, 3.5};
        // 打印所有数组元素
        for(int i = 0; i < myList.length; i++){System.out.println(myList[i] + " ");
        }
        for(double ele:myList){System.out.println(ele);
        }
        printArray(myList);
        // 计算所有元素的总和
        double total = 0;
        for(int i = 0;i < myList.length;i++){total += myList[i];
        }
        System.out.println("Total is" + total);
        // 查找最大元素
        double max = myList[0];
        for(int i = 1;i < myList.length; i++){if(myList[i] > max){max = myList[i];
            }
        }
        System.out.println("Max is" + max);

        double[] reverse = reverse(myList);
        printArray(reverse);
    }
}

Arrays 类
    java.util.Arrays 类能方便地操作数组, 它提供的所有方法都是静态的.
    1. 给数组赋值: 通过 fill 方法
    2. 对数组排序: 通缩 sort 方法, 按升序.
    3. 比较数组: 通过 equals 方法比较数组中元素值是否相等
    4. 查找数组元素: 通过 binarySearch 方法能对排序好的数组进行二分查找法操作
    public static void fill(int[] a, int val)
    public static void sort(Object[] a)
    public static boolean equals(long[] a, long[] a2)
    public static int binarySearch(Object[] a, Object key)

Java 日期时间

java.util 包提供了 Date 类来封装当前的日期和时间,Date 类提供两个构造函数来实例化 Date 对象
1.Date(): 使用当前日期和时间来初始化对象
2.Date(long millisec): 该参数从 1970 年一月一日起的微秒数
Date 对象创建后, 可调用下面的方法:
    boolean after(Date date): 若当调用此方法的 Date 对象在指定日期之后返回 true, 否则返回 false
    boolean before(Date date): 若当调用此方法的 Date 对象在指定日期之前返回 true, 否则返回 false
    Object clone(): 返回此对象的副本
    int compareTo(Date date): 比较当调用此方法的 Date 对象和指定日期。两者相等时候返回 0。调用对象在指定日期之前则返回负数。调用对象在指定日期之后则返回正数
    int compareTo(Object obj): 若 obj 是 Date 类型则操作等同于 compareTo(Date)。否则它抛出 ClassCastException
    boolean equals(Object date): 当调用此方法的 Date 对象和指定日期相等时候返回 true, 否则返回 false
    long getTime(): 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数
    int hashCode(): 返回此对象的哈希码值
    void setTime(long time): 用自 1970 年 1 月 1 日 00:00:00 GMT 以后 time 毫秒数设置时间和日期
    String toString(): 转换 Date 对象为 String 表示形式,并返回该字符串

使用 SimpleDateFormat 格式化日期
    import java.text.SimpleDateFormat;
    import java.util.Date;

    // 时间日期专题
    public class Main {public static void main(String[] args) {
            // 初始化 Date 对象
            Date date = new Date();
            // 使用 toString()函数显示日期时间
            System.out.println(date.toString());    //Thu Jun 06 17:13:04 CST 2019

            // 使用 SimpleDateFormat 格式化日期
            SimpleDateFormat ft = new SimpleDateFormat("E yyyy.MM.dd'at'hh:mm:ss a zzz");
            System.out.println("Current Date:" + ft.format(date)); //Current Date: 周四 2019.06.06 at 05:17:07 下午 CST
        }
    }
    
使用 printf 格式化日期
    import java.util.Date;
    public class DateDemo {public static void main(String args[]) {
         // 初始化 Date 对象
         Date date = new Date();

         // 使用 toString()显示日期和时间
         String str = String.format("Current Date/Time : %tc", date);

         System.out.printf(str);
      }
    }
    /---------------------------------------/
    import java.util.Date;
    public class DateDemo {public static void main(String args[]) {
           // 初始化 Date 对象
           Date date = new Date();
            
           // 使用 toString()显示日期和时间
           System.out.printf("%1$s %2$tB %2$td, %2$tY", 
                             "Due date:", date);
       }
    }
    DateFormat 格式化编码
    日期和时间转换字符
    解析字符串为时间
        SimpleDateFormat 类有一些附加的方法, 特别是 parse(), 它试图按照给定的 SimpleDateFormat 对象的格式化存储
        来解析字符串
        
    Java 休眠(sleep)
        可以让程序休眠
            Thread.sleep(5*60*10);
            
    测量时间
        long start = System.currentTimeMillis();
        System.out.println(new Date() + "\n");
        Thread.sleep(5*60*10);  // 休眠 10 秒, 不准确
        System.out.println(new Date() + "\n");
        long end = System.currentTimeMillis();
        long diff = end - start;
        System.out.println("Difference is :" + diff/1000);    // 秒

Calendar 类
    如何设置和获取日期数据的特定部分, 比如小时, 日, 或者分钟?
    使用 Calendar 类
        Calendar 类的功能要比 Date 类强大很多, 而且实现方式上也比 Date 类要复杂一些
        Calendar 类是一个抽象类, 在实际使用时实现特定的子类的对象, 创建对象的过程对程序员来说时透明的
        , 只需使用 getInstance 方法创建即可
        Calendar c = Calendar.getInstance();    // 默认是当前日期
        
GregorianCalendar 类
    Calendar 类实现了公历日历,GregorianCalendar 是 Calendar 类的一个具体实现
    import java.util.Calendar;
    import java.util.GregorianCalendar;

    public class Main {public static void main(String[] args){String months[] = {"Jan", "Feb", "Mar", "Apr",
                                "May", "Jun", "Jul", "Aug",
                                "Sep", "Oct", "Nov", "Dec"};

            int year;
            // 初始化 Gregorian 日历
            // 使用当前时间和日期
            // 默认为本地时间和时区
            GregorianCalendar gcalendar = new GregorianCalendar();
            // 显示当前时间和日期的信息
            System.out.print("Date:");
            System.out.print(months[gcalendar.get(Calendar.MONTH)]);
            System.out.print(""+ gcalendar.get(Calendar.DATE) +" ");
            System.out.println(year = gcalendar.get(Calendar.YEAR));
            System.out.print("Time:");
            System.out.print(gcalendar.get(Calendar.HOUR) + ":");
            System.out.print(gcalendar.get(Calendar.MINUTE) + ":");
            System.out.println(gcalendar.get(Calendar.SECOND));

            // 判断当前年份是否为润年
            if(gcalendar.isLeapYear(year)){System.out.println("当前年份是润年");
            }else{System.out.println("当前年份不是润年");
            }
        }
    }

JAVA 方法

方法是解决一类问题的步骤的有序组合
方法包含于类和对象中
方法在程序中被创建, 在其它地方被引用
方法的定义:
    修饰符 返回值类型 方法名(参数类型 参数名)
        ...
        方法体
        ...
        return 返回值
    main 方法是被 JVM 调用
重载的方法必须具有不同的参数列表, 不能仅仅依据修饰符或返回类型的不同来重载方法

构造方法:
    所有的类都有构造方法, 因为 JAVA 自动提供了一个默认构造方法, 它把所有成员初始化为 0.
    一旦你定义了自己的构造方法, 默认构造方法就会失效
finalize()方法:
    JAVA 允许定义这样的方法, 它在对象被垃圾收集器析构 (回收) 之前调用, 用来清除回收对象
    例如: 可以使用 finalize()方法来确保一个对象打开的文件被关闭了.
    在 finalize()方法里, 必须指定在对象销毁时候要执行的操作.
    

JAVA 流、文件、IO

输入流:表示从一个源读取数据
输出流: 表示向一个目标写数据
读取控制台输入:
    JAVA 的控制台输入由 System.in 完成
    为了获得一个绑定到控制台的字符流, 可以把 System.in 包装在 BufferedReader 对象中来创建一个字符流
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in))
        BufferedReader 对象创建后, 我们可以使用 read()方法从控制台读取一个字符, 或者用 readLine()方法来读取一个字符串
        
// 读写文件, 一个流被定义为一个数据序列, 输入流用于从源读取数据, 输出流用于向目标写数据
//Object---(OutputStream, InputStream)
//OutputStream---(FilterOutputStream,FileOutputStream,ByteArrayOutputStream)
//FilterOutputStream---(BufferedOutputStream, DataOutputStream, PrintStream)
//InputStream---(ByteArrayInputStream,FileInputStream,FilterInputStream,StringBufferInputStream,SequenceInputStream)
//FilterInputStream---(BufferedInputStream, DataInputStream, PushbackInputStream)

//FileInputStream
// 该流用于从文件读取数据, 用关键字 new 来创建对象

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

public class Main {public static void main(String[] args) {
        try{
            // 创建输入流对象来读取文件
            FileInputStream f = new FileInputStream("C:\\Users\\jasmintung\\meiju\\main.cpp");
            File ff = new File("C:\\Users\\jasmintung\\meiju\\main.cpp");
            // 也可使用一个文件对象来创建一个输入输出流对象来读取文件
            InputStream fs = new FileInputStream(ff);
        }catch(FileNotFoundException ex) {System.out.println(ex);
        }
    }
}
创建了 InputStream 对象, 就可以使用下面方法来读取流或进行其它的操作
    1:public void close() throws IOException{}
        关闭此文件输入流并释放与此流有关的所有系统资源。抛出 IOException 异常。2:protected void finalize()throws IOException {}
        这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出 IOException 异常
    3:public int read(int r)throws IOException{}
        这个方法从 InputStream 对象读取指定字节的数据。返回为整数值。返回下一字节数据,如果已经到结尾则返回 -1
    4:public int read(byte[] r) throws IOException{}
        这个方法从输入流读取 r.length 长度的字节。返回读取的字节数。如果是文件结尾则返回 -1
    5:public int available() throws IOException{}
        返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取的字节数。返回一个整数值
        
//FileOutputStream
该类用来创建一个文件并向文件中写数据

//FileReader,FileWriter 类

//JAVA 中的目录
创建目录: mkdir(),mkdirs()

// 读取目录:
    一个目录其实就是一个 File 对象, 它包含其它文件或文件夹
    如果创建一个 File 对象并且它是一个目录, 那么调用 isDirectory()方法会返回 true
    可通过调用该对象上的 list()方法, 来提取它包含的文件和文件夹的列表
    import java.io.File;

    public class DirList {public static void main(String args[]) {
          String dirname = "/tmp";
          File f1 = new File(dirname);
          if (f1.isDirectory()) {System.out.println( "Directory of" + dirname);
             String s[] = f1.list();
             for (int i=0; i < s.length; i++) {File f = new File(dirname + "/" + s[i]);
                if (f.isDirectory()) {System.out.println(s[i] + "is a directory");
                } else {System.out.println(s[i] + "is a file");
                }
             }
          } else {System.out.println(dirname + "is not a directory");
        }
      }
    }
    

JAVA 异常处理

异常是程序中的一些错误, 但并不是所有的错误都是异常, 并且错误有时候可以避免
异常发生的原因有很多, 通常包含一下几大类:
    1. 用户输入了非法数据
    2. 要打开的文件不存在
    3. 网络通信时连接中断, 或者 JVM 内存溢出
要理解 Java 异常处理是如何工作的,你需要掌握以下三种类型的异常:检查性异常: 最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的
Exception 类的层次:
    所有的异常类都是从 java.lang.Exception 类继承的子类
    Exception 类是 Throwable 类的子类.
    除了 Exception 类外,Throwable 还有一个子类 Error.
    
    在 Java 内置类中, 有大部分常用检查性和非检查性异常
    Java 语言定义了一些异常类在 java.lang 标准包中
    由于 java.lang 包是默认加载到所有的 Java 程序的, 所以大部分从运行时异常类继承而来的异常都可以直接使用
    
捕获异常:
    使用 try 和 catch 关键字可以捕获异常.

多重捕获块
    一个 try 代码块后面跟随多个 catch 代码块的情况叫多重捕获
throws/throw 关键字
    如果一个方法没有捕获一个检查性异常, 那么该方法必须使用 throws 关键字类声明
    throws 关键字放在方法签名的尾部
    
    import java.io.*;
    public class className
    {public void withdraw(double amount) throws RemoteException,
                                  InsufficientFundsException
       {// Method implementation}
       //Remainder of class definition
    }
    
finally 关键字
    finally 关键字用来创建在 try 代码块后面执行的代码块
    无论是否发生异常,finally 代码块中的代码总会被执行
    在 finally 代码块中, 可以运行清理类型等收尾善后性质的语句
    finally 代码块出现在 catch 代码块最后
    
    try{// 程序代码}catch(异常类型 1 异常的变量名 1){// 程序代码}catch(异常类型 2 异常的变量名 2){// 程序代码}finally{// 程序代码}
     
声明自定义异常
    在 java 中可以自定义异常
    注意:
        1. 所有异常都必须是 Throwable 的子类
        2. 如果希望写一个检查性异常类, 则需要继承 Exception 类
        3. 如果想写一个运行时异常, 那么需要继承 RuntimeException 类
    例如:
        class MyException extends Exception{//}
        
        一个异常类和其它任何类一样, 包含有变量和方法
    如何使用自定义的异常类:
        // 文件名 InsufficientFundsException.java
        import java.io.*;

        public class InsufficientFundsException extends Exception
        {
           private double amount;
           public InsufficientFundsException(double amount)
           {this.amount = amount;} 
           public double getAmount()
           {return amount;}
        }
        
        // 文件名称 CheckingAccount.java
        import java.io.*;

        public class CheckingAccount
        {
           private double balance;
           private int number;
           public CheckingAccount(int number)
           {this.number = number;}
           public void deposit(double amount)
           {balance += amount;}
           public void withdraw(double amount) throws
                                      InsufficientFundsException
           {if(amount <= balance)
              {balance -= amount;}
              else
              {
                 double needs = amount - balance;
                 throw new InsufficientFundsException(needs);
              }
           }
           public double getBalance()
           {return balance;}
           public int getNumber()
           {return number;}
        }
        
        // 文件名称 BankDemo.java
        public class BankDemo
        {public static void main(String [] args)
           {CheckingAccount c = new CheckingAccount(101);
              System.out.println("Depositing $500...");
              c.deposit(500.00);
              try
              {System.out.println("\nWithdrawing $100...");
                 c.withdraw(100.00);
                 System.out.println("\nWithdrawing $600...");
                 c.withdraw(600.00);
              }catch(InsufficientFundsException e)
              {
                 System.out.println("Sorry, but you are short $"
                                          + e.getAmount());
                 e.printStackTrace();}
            }
        }
通用异常
    在 java 中定义了两种类型的异常和错误
    1.JVM 异常: 由 JVM 抛出的异常或错误. 如:NullPointerException 类,
        ArrayIndexOutOfBoundsException 类,ClassCastException 类
    2. 程序级异常: 由程序或者 API 程序抛出的异常
        例如 IllegalArgumentException 类,IllegalStateException 类
        

JAVA ByteArrayInputStream 类

字节数组输入流在内存中创建一个字节数组缓冲区, 从输入流读取的数据保存在该字节数组缓冲区.
用法:
    ByteArrayInputStream bArray = new ByteArrayInputStream(byte[] a);
    ByteArrayInputStream bArray = new ByteArrayInputStream(byte[] a, int off, int len);
    
成功创建字节数组流对象后, 可用以下方法对流进行读操作或其它操作:
    1.public int read(): 从此输入流中读取下一个数据字节
    2.public int read(byte[] r, int off, int len): 将最多 len 个数据字节从此输入流读入字节数组
    3.public int available(): 返回可不发生阻塞地从此输入流读取的字节数
    4.public void mark(int read): 设置流中的当前标记位置
    5.public long skip(long n): 从此输入流中跳过 n 个输入字节
    
例子:
    import java.io.*;

    public class ByteStreamTest {public static void main(String args[])throws IOException {ByteArrayOutputStream bOutput = new ByteArrayOutputStream(12);

          while(bOutput.size()!= 10 ) {
             // 获取用户输入值
             bOutput.write(System.in.read());
          }

          byte b [] = bOutput.toByteArray();
          System.out.println("Print the content");
          for(int x= 0 ; x < b.length; x++) {
             // 打印字符
             System.out.print((char)b[x]  + " ");
          }
          System.out.println(" ");

          int c;

          ByteArrayInputStream bInput = new ByteArrayInputStream(b);

          System.out.println("Converting characters to Upper case");
          for(int y = 0 ; y < 1; y++) {while(( c= bInput.read())!= -1) {System.out.println(Character.toUpperCase((char)c));
             }
             bInput.reset();}
       }
    }
    

JAVA DataInputStream 类

数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 JAVA 数据类型
用法:
    DataInputStream dis = DataInputStream(InputStream in);
方法:
    1.public final int read(byte[] r, int off, int len)throws IOException
        从所包含的输入流中将 len 个字节读入一个字节数组中。如果 len 为 -1,则返回已读字节数
    2.Public final int read(byte [] b)throws IOException
        从所包含的输入流中读取一定数量的字节,并将它们存储到缓冲区数组 b 中
    3.public final Boolean readBooolean()throws IOException,
        public final byte readByte()throws IOException,
        public final short readShort()throws IOException
        public final Int readInt()throws IOException
        从输入流中读取字节,返回输入流中两个字节作为对应的基本数据类型返回值
    4.public String readLine() throws IOException
        从输入流中读取下一文本行
例子:
    DataInputStream 和 DataOutputStream 的使用,该例从文本文件 test.txt 中读取 5 行,并转换成大写字母,最后保存在另一个文件 test1.txt 中
    
    import java.io.*;

    public class Test{public static void main(String args[])throws IOException{

          DataInputStream d = new DataInputStream(new
                                   FileInputStream("test.txt"));

          DataOutputStream out = new DataOutputStream(new
                                   FileOutputStream("test1.txt"));

          String count;
          while((count = d.readLine()) != null){String u = count.toUpperCase();
              System.out.println(u);
              out.writeBytes(u + ",");
          }
          d.close();
          out.close();}
    }
    

JAVA ByteArrayOutputStream 类

字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中
用法:
    OutputStream bOut = new ByteArrayOutputStream();
    OutputStream bOut = new ByteArrayOutputStream(int a)
方法:
    1.public void reset()
        将此字节数组输出流的 count 字段重置为零,从而丢弃输出流中目前已累积的所有数据输出
    2.public byte[] toByteArray()
        创建一个新分配的字节数组。数组的大小和当前输出流的大小,内容是当前输出流的拷贝
    3.public String toString()
        将缓冲区的内容转换为字符串,根据平台的默认字符编码将字节转换成字符
    4.public void write(int w)
        将指定的字节写入此字节数组输出流
    5.public void write(byte []b, int of, int len)
        将指定字节数组中从偏移量 off 开始的 len 个字节写入此字节数组输出流
    6.public void writeTo(OutputStream outSt)
        将此字节数组输出流的全部内容写入到指定的输出流参数中
    
    

JAVA DataoutputStream 类

数据输出流允许应用程序以与机器无关方式将 Java 基本数据类型写到底层输出流
用法:
    DataOutputStream out = DataOutputStream(OutputStream  out);
方法:
    1.public final void write(byte[] w, int off, int len)throws IOException
        将指定字节数组中从偏移量 off 开始的 len 个字节写入此字节数组输出流
    2.Public final int write(byte [] b)throws IOException
        将指定的字节写入此字节数组输出流
    3.public final void writeBooolean()throws IOException,
        public final void writeByte()throws IOException,
        public final void writeShort()throws IOException,
        public final void writeInt()throws IOException
        这些方法将指定的基本数据类型以字节的方式写入到输出流
    4.Public void flush()throws IOException
        刷新此输出流并强制写出所有缓冲的输出字节
    5.public final void writeBytes(String s) throws IOException
        将字符串以字节序列写入到底层的输出流,字符串中每个字符都按顺序写入,并丢弃其高八位
    

JAVA File 类

JAVA 文件类以抽象的方式代表文件名和目录路径名. 该类主要用于文件和目录的创建, 文件的查找和文件的删除等
File 对象代表磁盘中实际存在的文件和目录
用法:
    File(File parent, String child);
    File(String pathname);
    File(String parent, String child);
    File(URI uri);
    
方法:
    1    public String getName()
    返回由此抽象路径名表示的文件或目录的名称。2    public String getParent()、返回此抽象路径名的父路径名的路径名字符串,如果此路径名没有指定父目录,则返回 null。3    public File getParentFile()
    返回此抽象路径名的父路径名的抽象路径名,如果此路径名没有指定父目录,则返回 null。4    public String getPath()
    将此抽象路径名转换为一个路径名字符串。5    public boolean isAbsolute()
    测试此抽象路径名是否为绝对路径名。6    public String getAbsolutePath()
    返回抽象路径名的绝对路径名字符串。7    public boolean canRead()
    测试应用程序是否可以读取此抽象路径名表示的文件。8    public boolean canWrite()
    测试应用程序是否可以修改此抽象路径名表示的文件。9    public boolean exists()
    测试此抽象路径名表示的文件或目录是否存在。10    public boolean isDirectory()
    测试此抽象路径名表示的文件是否是一个目录。11    public boolean isFile()
    测试此抽象路径名表示的文件是否是一个标准文件。12    public long lastModified()
    返回此抽象路径名表示的文件最后一次被修改的时间。13    public long length()
    返回由此抽象路径名表示的文件的长度。14    public boolean createNewFile() throws IOException
    当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件。15    public boolean delete()
     删除此抽象路径名表示的文件或目录。16    public void deleteOnExit()
    在虚拟机终止时,请求删除此抽象路径名表示的文件或目录。17    public String[] list()
    返回由此抽象路径名所表示的目录中的文件和目录的名称所组成字符串数组。18    public String[] list(FilenameFilter filter)
    返回由包含在目录中的文件和目录的名称所组成的字符串数组,这一目录是通过满足指定过滤器的抽象路径名来表示的。19    public File[] listFiles()
      返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。20    public File[] listFiles(FileFilter filter)
    返回表示此抽象路径名所表示目录中的文件和目录的抽象路径名数组,这些路径名满足特定过滤器。21    public boolean mkdir()
    创建此抽象路径名指定的目录。22    public boolean mkdirs()
    创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。23    public boolean renameTo(File dest)
     重新命名此抽象路径名表示的文件。24    public boolean setLastModified(long time)
    设置由此抽象路径名所指定的文件或目录的最后一次修改时间。25    public boolean setReadOnly()
    标记此抽象路径名指定的文件或目录,以便只可对其进行读操作。26    public static File createTempFile(String prefix, String suffix, File directory) throws IOException
    在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。27    public static File createTempFile(String prefix, String suffix) throws IOException
    在默认临时文件目录中创建一个空文件,使用给定前缀和后缀生成其名称。28    public int compareTo(File pathname)
    按字母顺序比较两个抽象路径名。29    public int compareTo(Object o)
    按字母顺序比较抽象路径名与给定对象。30    public boolean equals(Object obj)
    测试此抽象路径名与给定对象是否相等。31    public String toString()
     返回此抽象路径名的路径名字符串
     
例子:
    import java.io.File;
    public class DirList {public static void main(String args[]) {
          String dirname = "/java";
          File f1 = new File(dirname);
          if (f1.isDirectory()) {System.out.println( "Directory of" + dirname);
             String s[] = f1.list();
             for (int i=0; i < s.length; i++) {File f = new File(dirname + "/" + s[i]);
                if (f.isDirectory()) {System.out.println(s[i] + "is a directory");
                } else {System.out.println(s[i] + "is a file");
                }
             }
          } else {System.out.println(dirname + "is not a directory");
        }
      }
    }

JAVA FileReader 类

FileReader 类从 InputStreamReader 类继承而来, 该类按字符读取流中数据.
用法:
    FileReader(File file);
    FileReader(FileDescriptor fd);
    FileReader(String fileName;
方法:
    1    public int read() throws IOException
    读取单个字符,返回一个 int 型变量代表读取到的字符
    2    public int read(char [] c, int offset, int len)
    读取字符到 c 数组,返回读取到字符的个数
例子:
    import java.io.*;
    public class FileRead{public static void main(String args[])throws IOException{File file = new File("Hello1.txt");
          // 创建文件
          file.createNewFile();
          // creates a FileWriter Object
          FileWriter writer = new FileWriter(file); 
          // 向文件写入内容
          writer.write("This\n is\n an\n example\n"); 
          writer.flush();
          writer.close();
          // 创建 FileReader 对象
          FileReader fr = new FileReader(file); 
          char [] a = new char[50];
          fr.read(a); // 读取数组中的内容
          for(char c : a)
              System.out.print(c); // 一个一个打印字符
          fr.close();}
    }
    

JAVA FileWriter 类

FileWriter 类从 OutputStreamReader 类继承而来。该类按字符向流中写入数据
用法:
    FileWriter(File file);
    FileWriter(File file, boolean append);
    FileWriter(FileDescriptor fd);
    FileWriter(String fileName, boolean append);
方法:
    1    public void write(int c) throws IOException
    写入单个字符 c。2    public void write(char [] c, int offset, int len)
    写入字符数组中开始为 offset 长度为 len 的某一部分。3    public void write(String s, int offset, int len)
    写入字符串中开始为 offset 长度为 len 的某一部分。

Java 继承

JAVA 中, 类的继承是单一继承, 一个子类只能拥有一个父类
继承中最常使用的两个关键字: extends 和 implements
这两个关键字的使用决定了一个对象和另一个对象是否是 IS-A(是一个)关系
通过使用这两个关键字, 我们能实现一个对象获取另一个对象的属性
所有 JAVA 的类均是由 java.lang.Object 类继承而来的, 所以 Object 是所有类的祖先类,
除了 Object 外, 所有类必须有一个父类
// A.java
public class A {
    private int i;
    protected int j;
 
    public void func() {}
}
 
// B.java
public class B extends A {

}
B 由 A 继承而来的, B 是 A 的子类. 而 A 是 Object 的子类, 这里可以不显示地声明
作为子类,B 的实例拥有 A 所有的成员变量, 但对于 private 的成员变量 B 却没有访问权限, 这保障了 A 的封装性

什么是 IS- A 关系?
    一个对象是另一个对象的一个分类
    public class Animal{ }

    public class Mammal extends Animal{ }

    public class Reptile extends Animal{ }

    public class Dog extends Mammal{ }
    分析以上示例中的 IS- A 关系, 如下:Mammal IS-A Animal
        Reptile IS-A Animal
        Dog IS-A Mammal
        因此 : Dog IS-A Animal
通过使用关键字 extends, 子类可以继承父类的除 private 属性外所有的属性.
我们通过使用 instanceof 操作符, 能够确定 Mammal IS-A Animal(返回 true or false)
    public class Dog extends Mammal{public static void main(String args[]){Animal a = new Animal();
          Mammal m = new Mammal();
          Dog d = new Dog();

          System.out.println(m instanceof Animal);    //true
          System.out.println(d instanceof Mammal);    //true
          System.out.println(d instanceof Animal);    //true
       }
    }

implements 关键字
    使用在类继承接口的情况下. 这种情况下不能使用 extends

HAS-A 关系
    代表类和它的成员之间的从属关系. 有助于代码的重用和减少代码的错误
    例子:
        public class Vehicle{}
        public class Speed{}
        public class Van extends Vehicle{private Speed sp;}
        Van 类和 Speed 类是 HAS- A 关系(Van 有一个 Speed), 这样就不用将 Speed 类的全部代码粘贴到 Van 类中了
        并且 Speed 类也可以重复利用于多个应用程序
    
JAVA 只支持单继承(继承基本类和抽象类), 但是我们可以用接口来实现(多继承接口来实现)
    public class Apple extends Fruit implements Fruit1, Fruit2{ }
    
一般我们继承基本类和抽象类用 extends 关键字, 实现接口类的继承用 implements 关键字

JAVA 重写 Override 与重载 Overload

重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参不能改变
重写的好处在于子类可以根据需求, 定义特定于自己的行为
也就是说子类能够根据需要实现父类的方法
例子:
    class Animal{public void move(){System.out.println("动物可以移动");
        }
    }
    
    class Dog extends Animal{public void move(){System.out.println("dog can run and walk");
        }
    }
    
    public class TestDog{public static void main(String args[]){Animal a = new Animal();
            Animal b = new Dog();    //Dog 对象
            a.move();    // 执行 Animal 类的方法
            b.moev();    // 执行 Dog 类的方法}
    }
    
    在上面的例子中可以看到,尽管 b 属于 Animal 类型,但是它运行的是 Dog 类的 move 方法。这是由于在编译阶段,只是检查参数的引用类型。然而在运行时,Java 虚拟机 (JVM) 指定对象的类型并且运行该对象的方法。因此在上面的例子中,之所以能编译成功,是因为 Animal 类中存在 move 方法,然而运行时,运行的是特定对象的方法
    
思考例子:
    class Animal{public void move(){System.out.println("动物可以移动");
       }
    }

    class Dog extends Animal{public void move(){System.out.println("狗可以跑和走");
       }
       public void bark(){System.out.println("狗可以吠叫");
       }
    }

    public class TestDog{public static void main(String args[]){Animal a = new Animal(); // Animal 对象
          Animal b = new Dog(); // Dog 对象

          a.move();// 执行 Animal 类的方法
          b.move();// 执行 Dog 类的方法
          b.bark();}
    }
    运行结果:
        TestDog.java:30: cannot find symbol
        symbol  : method bark()
        location: class Animal
                        b.bark();
                        
    该程序将抛出一个编译错误, 因为 b 的引用类型 Animal 没有 bark 方法
    
方写重写的规则
    参数列表必须完全与被重写方法的相同;返回类型必须完全与被重写方法的返回类型相同;访问权限不能比父类中被重写的方法的访问权限更高。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。父类的成员方法只能被它的子类重写。声明为 final 的方法不能被重写。声明为 static 的方法不能被重写,但是能够被再次声明。如果一个方法不能被继承,那么该方法不能被重写。子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。构造方法不能被重写。如果不能继承一个方法,则不能重写这个方法

Super 关键字的使用
    当需要在子类中调用父类的被重写方法时, 要使用 super 关键字
    class Animal{public void move(){System.out.println("anmial can move");
        }
    }
    
    class Dog extends Animall{public void move(){super.move();    // 调用 super 类的方法
            System.out.println("dog can run and walk");
        }
    }
    
    public class TestDog{public static void main(String args[]){Animal b = new Dog();
            b.move();}
    }
    
重载(Overload)
    重载(overloading) 是在一个类里面, 方法名字相同, 而参数不同. 返回类型呢?可以相同也可以不同
    
    重载规则:
        被重载的方法必须改变参数列表;被重载的方法可以改变返回类型;被重载的方法可以改变访问修饰符;被重载的方法可以声明新的或更广的检查异常;方法能够在同一个类中或者在一个子类中被重载
        
    例子:
        public class Overloading {public int test(){System.out.println("test1");
            return 1;
        }
     
        public void test(int a){System.out.println("test2");
        }    
     
        // 以下两个参数类型顺序不同
        public String test(int a,String s){System.out.println("test3");
            return "returntest3";
        }    
     
        public String test(String s,int a){System.out.println("test4");
            return "returntest4";
        }    
     
        public static void main(String[] args){Overloading o = new Overloading();
            System.out.println(o.test());
            o.test(1);
            System.out.println(o.test(1,"test3"));
            System.out.println(o.test("test4",1));
        }

重写与重载之间的区别
    区别点       重载方法            重写方法
    参数列表    必须修改         一定不能修改
    返回类型    可以修改         一定不能修改
    异常        可以修改         可以减少或删除,一定不能抛出新的或者更广的异常
    访问        可以修改         一定不能做更严格的限制(可以降低限制)

JAVA 多态

多态, 是同一个行为具有多个不同表现形式或形态的能力
比如我们说 "宠物" 这个对象,它就有很多不同的表达或实现,比如有小猫、小狗、蜥蜴等等。那么我到宠物店说 "请给我一只宠物",服务员给我小猫、小狗或者蜥蜴都可以,我们就说 "宠物" 这个对象就具备多态性

例子:
    public interface Vegetarian{}
    public class Animal{}
    public class Deer extends Animal implements Vegetarian{}
    此时,Deer 类具有多重继承, 具有多态性
        一个 Deer IS-A(是一个)Animal
        一个 Deer IS-A(是一个)Vegetarian
        一个 Deer IS-A(是一个)Deer
        一个 Deer IS-A(是一个)Object
在 JAVA 中, 所有的对象都具有多态性.
访问一个对象的唯一方法是: 通过引用型变量
引用型变量只能有一种类型, 一旦被声明, 引用型变量的类型就不能被改变了
引用型变量不仅能够被重置为其它对象, 前提是这些对象没有被声明为 final.
还可以引用和它类型相同的或者相兼容的对象. 它可以声明为类类型或者接口类型

当我们将引用变量应用于 Deer 对象的引用时, 下面的声明时合法的:
    Deer d = new Deer();
    Animal a = d;
    Vegetarian v = d;
    Object o = d;
    所有的引用型变量 d,a,v,o 都指向堆中相同的 Deer 对象

虚方法(可以理解为 C ++ 中的虚函数)
    当子类对象调用重载的方法时, 调用的是子类的方法, 而不是父类中被重载的方法
    想要调用父类中被重载的方法, 必须使用关键字 super

    例子(仔细看):
        /* 文件名 : Employee.java */
        public class Employee
        {
           private String name;
           private String address;
           private int number;
           public Employee(String name, String address, int number)
           {System.out.println("Constructing an Employee");
              this.name = name;
              this.address = address;
              this.number = number;
           }
           public void mailCheck()
           {
              System.out.println("Mailing a check to" + this.name
               + " " + this.address);
           }
           public String toString()
           {return name + "" + address +" " + number;}
           public String getName()
           {return name;}
           public String getAddress()
           {return address;}
           public void setAddress(String newAddress)
           {address = newAddress;}
           public int getNumber()
           {return number;}
        }
        
        /* 文件名 : Salary.java */
        public class Salary extends Employee
        {
           private double salary; //Annual salary
           public Salary(String name, String address, int number, double
              salary)
           {super(name, address, number);
               setSalary(salary);
           }
           public void mailCheck()
           {System.out.println("Within mailCheck of Salary class");
               System.out.println("Mailing check to" + getName()
               + "with salary" + salary);
           }
           public double getSalary()
           {return salary;}
           public void setSalary(double newSalary)
           {if(newSalary >= 0.0)
               {salary = newSalary;}
           }
           public double computePay()
           {System.out.println("Computing salary pay for" + getName());
              return salary/52;
           }
        }
        
        /* 文件名 : VirtualDemo.java */
        public class VirtualDemo
        {public static void main(String [] args)
           {Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
              Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
              System.out.println("Call mailCheck using Salary reference --");
              s.mailCheck();
              System.out.println("\n Call mailCheck using Employee reference--");
              e.mailCheck();}
        }
        
        运行结果:
            Constructing an Employee
            Constructing an Employee
            Call mailCheck using Salary reference --
            Within mailCheck of Salary class
            Mailing check to Mohd Mohtashim with salary 3600.0

            Call mailCheck using Employee reference--
            Within mailCheck of Salary class
            Mailing check to John Adams with salary 2400.0

        例子中,我们实例化了两个 Salary 对象。一个使用 Salary 引用 s,另一个使用 Employee 引用。编译时,编译器检查到 mailCheck()方法在 Salary 类中的声明。在调用 s.mailCheck()时,Java 虚拟机 (JVM) 调用 Salary 类的 mailCheck()方法。因为 e 是 Employee 的引用,所以调用 e 的 mailCheck()方法则有完全不同的结果。当编译器检查 e.mailCheck()方法时,编译器检查到 Employee 类中的 mailCheck()方法。在编译的时候,编译器使用 Employee 类中的 mailCheck()方法验证该语句,但是在运行的时候,Java 虚拟机 (JVM) 调用的是 Salary 类中的 mailCheck()方法。该行为被称为虚拟方法调用,该方法被称为虚拟方法。Java 中所有的方法都能以这种方式表现,借此,重写的方法能在运行时调用,不管编译的时候源代码中引用变量是什么数据类型。

JAVA 抽象类

在面向对象的概念中, 所有的对象都是通过类来描绘的, 但是反过来, 并不是所有的类都是用来描绘对象的,
如果一个类中没有包含足够的信息来描述一个具体的对象, 这样的类就是抽象类

抽象类除了不能实例化对象之外, 类的其它功能依然存在, 成员变量, 成员方法和构造方法的访问方式和普通类一样
由于抽象类不能实例化对象, 所以抽象类必须被继承, 才能被使用. 也就是因为这个原因, 通常在设计阶段决定要不要设计抽象类

定义一个抽象类:
    /* 文件名 : Employee.java */
    public abstract class Employee
    {
       private String name;
       private String address;
       private int number;
       public Employee(String name, String address, int number)
       {System.out.println("Constructing an Employee");
          this.name = name;
          this.address = address;
          this.number = number;
       }
       public double computePay()
       {System.out.println("Inside Employee computePay");
         return 0.0;
       }
       public void mailCheck()
       {
          System.out.println("Mailing a check to" + this.name
           + " " + this.address);
       }
       public String toString()
       {return name + "" + address +" " + number;}
       public String getName()
       {return name;}
       public String getAddress()
       {return address;}
       public void setAddress(String newAddress)
       {address = newAddress;}
       public int getNumber()
       {return number;}
    }
    该 Employee 类没有什么不同, 尽管该类是抽象类, 但是它仍然有 3 个成员变量,7 个成员方法和 1 个构造方法.
    现在如果你尝试如下的例子:
        /* 文件名 : AbstractDemo.java */
        public class AbstractDemo
        {public static void main(String [] args)
           {
              /* 以下是不允许的,会引发错误 */
              Employee e = new Employee("George W.", "Houston, TX", 43);

              System.out.println("\n Call mailCheck using Employee reference--");
              e.mailCheck();}
        }
        当你尝试编译 AbstractDemo 类时, 会产生如下错误:Employee.java:46: Employee is abstract; cannot be instantiated
            Employee e = new Employee("George W.", "Houston, TX", 43);
               ^
            1 error
            
继承抽象类
    /* 文件名 : Salary.java */
    public class Salary extends Employee
    {
       private double salary; //Annual salary
       public Salary(String name, String address, int number, double
          salary)
       {super(name, address, number);
           setSalary(salary);
       }
       public void mailCheck()
       {System.out.println("Within mailCheck of Salary class");
           System.out.println("Mailing check to" + getName()
           + "with salary" + salary);
       }
       public double getSalary()
       {return salary;}
       public void setSalary(double newSalary)
       {if(newSalary >= 0.0)
           {salary = newSalary;}
       }
       public double computePay()
       {System.out.println("Computing salary pay for" + getName());
          return salary/52;
       }
    }
    尽管我们不能实例化一个 Employee 类的对象, 但是如果我们实例化一个 Salary 类对象, 该对象将从 Employee 类继承 3 个成员变量和 7 个成员方法
    
抽象方法
    如果想设计这样一个类, 该类包含一个特别的成员方法, 该方法的具体实现由它的子类确定,
    那么可以在父类中声明该方法为抽象方法
    
    Abstract 关键词同样可以用来声明抽象方法, 抽象方法只包含一个方法名, 而没有方法体
    抽象方法没有定义, 方法名后面直接跟一个分号, 而不是花括号
    
    public abstract class Employee
    {
       private String name;
       private String address;
       private int number;
       
       public abstract double computePay();
       
       // 其余代码
    }
    
    声明抽象方法会造成以下两个结果
        1. 如果一个类包含抽象方法, 那么该类必须是抽象类
        2. 任何子类必须重写该类的抽象方法, 或者声明自身为抽象类
    继承抽象方法的子类必须重载该方法. 否则, 该子类也必须声明为抽象类.
    最终, 必须有子类实现该抽象类方法
    如果 Salary 类继承了 Employee 类, 那么它必须实现 computePay()方法
        /* 文件名 : Salary.java */
        public class Salary extends Employee
        {
           private double salary; // Annual salary
          
           public double computePay()
           {System.out.println("Computing salary pay for" + getName());
              return salary/52;
           }

           // 其余代码
        }

JAVA 封装(Encapsulation)

防止该类的代码和数据被外部类定义的代码随机访问
要访问该类的代码和数据, 必须通过严格的接口控制
封装最主要的功能在于我们能修改自己的实现代码, 而不用修改那些调用我们代码的程序片段
适当的封装可以让程式码更容易理解与维护.
例子:
    /* 文件名: EncapTest.java */
    public class EncapTest{

       private String name;
       private String idNum;
       private int age;

       public int getAge(){return age;}

       public String getName(){return name;}

       public String getIdNum(){return idNum;}

       public void setAge(int newAge){age = newAge;}

       public void setName(String newName){name = newName;}

       public void setIdNum(String newId){idNum = newId;}
    }
    以上实例中 public 方法是外部类访问该类成员变量的入口
    

JAVA 接口

在 java 编程中是一个抽象类型, 是抽象方法的集合. 接口通常以 interface 来声明.
一个类通过继承接口的方式, 从而来继承接口的抽象方法

接口并不是类, 类描述对象的属性和方法, 接口则包含要类实现的方法.
除非实现接口的类是抽象类, 否则该类要定义接口中的所有方法
接口与类相似点:一个接口可以有多个方法。接口文件保存在.java 结尾的文件中,文件名使用接口名。接口的字节码文件保存在.class 结尾的文件中。接口相应的字节码文件必须在与包名称相匹配的目录结构中。接口与类的区别:接口不能用于实例化对象。接口没有构造方法。接口中所有的方法必须是抽象方法。接口不能包含成员变量,除了 static 和 final 变量。接口不是被类继承了,而是要被类实现。接口支持多重继承。接口的声明:
    [可见度] interface 接口名称 [extends 其他的类名] {
        // 声明变量
        // 抽象方法
    }
    /* 文件名 : NameOfInterface.java */
    import java.lang.*;
    // 引入包

    public interface NameOfInterface
    {
       // 任何类型 final, static 字段
       // 抽象方法
    }
接口有以下特性:接口是隐式抽象的,当声明一个接口的时候,不必使用 abstract 关键字。接口中每一个方法也是隐式抽象的,声明时同样不需要 abstract 关键子。接口中的方法都是公有的

接口的实现
    当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类
    ... implements 接口名称[, 其他接口, 其他接口..., ...] ...
    
    例子:
        /* 文件名 : MammalInt.java */
        public class MammalInt implements Animal{public void eat(){System.out.println("Mammal eats");
           }

           public void travel(){System.out.println("Mammal travels");
           } 

           public int noOfLegs(){return 0;}

           public static void main(String args[]){MammalInt m = new MammalInt();
              m.eat();
              m.travel();}
        }

接口的继承
    一个接口能继承另一个接口, 和类之间的继承方式比较相似. 接口的继承使用 extends 关键字, 子接口继承父接口的方法
    // 文件名: Sports.java
    public interface Sports
    {public void setHomeTeam(String name);
       public void setVisitingTeam(String name);
    }

    // 文件名: Football.java
    public interface Football extends Sports
    {public void homeTeamScored(int points);
       public void visitingTeamScored(int points);
       public void endOfQuarter(int quarter);
    }

    // 文件名: Hockey.java
    public interface Hockey extends Sports
    {public void homeGoalScored();
       public void visitingGoalScored();
       public void endOfPeriod(int period);
       public void overtimePeriod(int ot);
    }
    Hockey 接口自己声明了四个方法, 从 Sports 接口继承了两个方法, 这样, 实现 Hockey 接口的类需要实现六个方法。相似的, 实现 Football 接口的类需要实现五个方法, 其中两个来自于 Sports 接口
    
接口的多重继承
    在接口的多重继承中 extends 关键字只需要使用一次, 在其后跟着继承接口
    public interface Hockey extends Sports, Event

标记接口
    最常用的继承接口是没有包含任何方法的接口
    标识接口是没有任何方法和属性的接口. 它仅仅表明它的类属于一个特定的类型, 供其他代码来测试允许做一些事情
    标识接口作用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权
    例如:java.awt.event 包中的 MouseListener 接口继承的 java.util.EventListener 接口定义如下
        package java.util;
        public interface EventListener
        {}
    没有任何方法的接口被称为标记接口。标记接口主要用于以下两种目的:1. 建立一个公共的父接口:正如 EventListener 接口,这是由几十个其他接口扩展的 Java API,
        你可以使用一个标记接口来建立一组接口的父接口。例如:当一个接口继承了 EventListener 接口,Java 虚拟机 (JVM) 就知道该接口将要被用于一个事件的代理方案。2. 向一个类添加数据类型:这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),
        但是该类通过多态性变成一个接口类型
        

JAVA 包

为了更好的组织类,JAVA 提供了包机制, 用于区别类名的命名空间
包的作用:
    1. 把功能相似或相关的类或接口组织在同一个包中, 方便类的查找和使用
    2. 如同文件夹一样, 包也采用树形目录的存储方式. 同一个包中的类名字是不同的,
        不同的包中的类的名字是可以相同的, 当同时调用两个不同包中相同类名的类时,
        应该加上包名加以区别. 包可避免名字冲突
    3. 包限定了访问权限, 拥有包访问权限的类才能访问某个包中类
包语句的语法格式:
    package pkg1[. pkg2...]

创建包
    包声明应该放在源文件的第一行, 每个源文件只能有一个包声明, 这个文件中的每个类型都应用于它
    如果一个源文件中没有使用包声明, 那么其中的类, 函数, 枚举, 注释等将被放在一个无名的包(unnamed package)中.
    
    /* 文件名: Animal.java */
    package animals;

    interface Animal {public void eat();
       public void travel();}
    
    package animals;

    /* 文件名 : MammalInt.java */
    public class MammalInt implements Animal{public void eat(){System.out.println("Mammal eats");
       }

       public void travel(){System.out.println("Mammal travels");
       } 

       public int noOfLegs(){return 0;}

       public static void main(String args[]){MammalInt m = new MammalInt();
          m.eat();
          m.travel();}
    }
    
import 关键字
    为了能够使用某一个包的成员, 我们需要在 java 程序中明确导入该包. 使用 "import" 语句可完成此功能
    在 java 源文件中 import 语句应位于 package 语句之后, 所有类的定义之前, 可以没有, 也可以有多条, 其语法格式为
        import package1[.package2…].(classname|*);
        如果在一个包中, 一个类想要使用本包中的另一个类, 那么该包名可以省略
        
    几种导入包的写法:
        1.payroll.Employee
        2.import payroll.*;
        3.import payroll.Employee;
        
    类文件中可以包含任意数量的 import 声明.import 声明必须在包声明之后, 类声明之前
    
package 的目录结构
    管理 java 中文件的一种简单方式:
        将类、接口等类型的源码放在一个文本中, 这个文件的名字就是这个类型的名字, 并以.java 作为扩展名
        接下来, 把源文件放在一个目录中, 这个目录要对应类所在包的名字
        
        通常, 一个公司使用它互联网域名的颠倒形式来作为它的包名. 例如:互联网域名是 apple.com, 所有的包名都以 com.apple 开头.
        包名中的每一个部分对应一个子目录
        
        例如:这个公司有一个 com.apple.computers 的包,这个包包含一个叫做 Dell.java 的源文件,那么相应的,应该有如下面的一连串子目录:....\com\apple\computers\Dell.java
            编译的时候,编译器为包中定义的每个类、接口等类型各创建一个不同的输出文件,输出文件的名字就是这个类型的名字,并加上.class 作为扩展后缀。例如:// 文件名: Dell.java
                package com.apple.computers;
                public class Dell{ }
                class Ups{ }
                用 - d 选项来编译这个文件:
                $javac -d . Dell.java    
                这样会像下面这样放置编译了的文件:.\com\apple\computers\Dell.class.\com\apple\computers\Ups.class
                编译之后的.class 文件应该和.java 源文件一样,它们放置的目录应该跟包的名字对应起来。但是,并不要求.class 文件的路径跟相应的.java 的路径一样。你可以分开来安排源码和类的目录:
                <path-one>\sources\com\apple\computers\Dell.java
                <path-two>\classes\com\apple\computers\Dell.class
                这样,你可以将你的类目录分享给其他的编程人员,而不用透露自己的源码。用这种方法管理源码和类文件可以让编译器和 java 虚拟机(JVM)可以找到你程序中使用的所有类型。类目录的绝对路径叫做 class path。设置在系统变量 CLASSPATH 中。编译器和 java 虚拟机通过将 package 名字加到 class path 后来构造.class 文件的路径。<path- two>\classes 是 class path,package 名字是 com.apple.computers, 而编译器和 JVM 会在 <path-two>\classes\com\apple\compters 中找.class 文件。一个 class path 可能会包含好几个路径。多路径应该用分隔符分开。默认情况下,编译器和 JVM 查找当前目录。JAR 文件按包含 Java 平台相关的类,所以他们的目录默认放在了 class path 中        

设置 CLASSPATH 系统变量
    用下面的命令显示当前的 CLASSPATH 变量:Windows 平台(DOS 命令行下)-> C:\> set CLASSPATH
        UNIX 平台(Bourne shell 下)-> % echo $CLASSPATH
    删除当前 CLASSPATH 变量内容:Windows 平台(DOS 命令行下)-> C:\> set CLASSPATH=
        UNIX 平台(Bourne shell 下)-> % unset CLASSPATH; export CLASSPATH
    设置 CLASSPATH 变量:
        Windows 平台(DOS 命令行下)-> set CLASSPATH=C:\users\jack\java\classes
        UNIX 平台(Bourne shell 下)-> % CLASSPATH=/home/jack/java/classes; export CLASSPATH
        
        

JAVA Enumeration 接口

Enumeration 接口中定义了一些方法, 通过这些方法可以枚举对象集合中的元素
这种传统接口已被迭代器取代, 虽然 Enumeration 还未被丢弃, 但现代代码中很少使用了.
它还使用在诸如 Vector 和 Properties 这些传统类所定义的方法中, 除此之外, 还用在一些 API 类
例子:
    import java.util.Vector;
    import java.util.Enumeration;

    public class EnumerationTester {public static void main(String args[]) {
          Enumeration days;
          Vector dayNames = new Vector();
          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()); 
          }
       }
    }
    运行结果:
        Sunday
        Monday
        Tuesday
        Wednesday
        Thursday
        Friday
        Saturday

JAVA Bitset 类

一个 Bitset 类创建一种特殊类型的数组来保存位值.BitSet 中数组大小会随需要增加. 这和位向量 (vector of bits) 比较类似
方法:很多, 直接看网址:https://code.ziqiangxuetang.com/java/java-bitset-class.html
例子:
    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("\nInitial pattern in bits2:");
         System.out.println(bits2);

         // AND bits
         bits2.and(bits1);
         System.out.println("\nbits2 AND bits1:");
         System.out.println(bits2);

         // OR bits
         bits2.or(bits1);
         System.out.println("\nbits2 OR bits1:");
         System.out.println(bits2);

         // XOR bits
         bits2.xor(bits1);
         System.out.println("\nbits2 XOR bits1:");
         System.out.println(bits2);
      }
    }
    以上实例编译运行结果如下:
    Initial pattern in bits1:
    {0, 2, 4, 6, 8, 10, 12, 14}

    Initial pattern in bits2:
    {1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14}

    bits2 AND bits1:
    {2, 4, 6, 8, 12, 14}

    bits2 OR bits1:
    {0, 2, 4, 6, 8, 10, 12, 14}

    bits2 XOR bits1:
    {}
    

JAVA Vector 类

Vector 类实现了一个动态数组. 和 ArrayList 相似
    Vector 时同步访问的
    Vector 包含了许多传统的方法, 这些方法不属于集合框架
Vector 主要用在事先不知道数组的大小, 或者只是需要一个可以改变大小的数组的情况
方法:
    很多, 看网址:https://code.ziqiangxuetang.com/java/java-vector-class.html
例子:
    import java.util.*;

    public class VectorDemo {public static void main(String args[]) {
          // initial size is 3, increment is 2
          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.addElement(new Integer(2));
          v.addElement(new Integer(3));
          v.addElement(new Integer(4));
          System.out.println("Capacity after four additions:" +
              v.capacity());

          v.addElement(new Double(5.45));
          System.out.println("Current capacity:" +
          v.capacity());
          v.addElement(new Double(6.08));
          v.addElement(new Integer(7));
          System.out.println("Current capacity:" +
          v.capacity());
          v.addElement(new Float(9.4));
          v.addElement(new Integer(10));
          System.out.println("Current capacity:" +
          v.capacity());
          v.addElement(new Integer(11));
          v.addElement(new Integer(12));
          System.out.println("First element:" +
             (Integer)v.firstElement());
          System.out.println("Last element:" +
             (Integer)v.lastElement());
          if(v.contains(new Integer(3)))
             System.out.println("Vector contains 3.");
          // enumerate the elements in the vector.
          Enumeration vEnum = v.elements();
          System.out.println("\nElements in vector:");
          while(vEnum.hasMoreElements())
             System.out.print(vEnum.nextElement() + " ");
          System.out.println();}
    }
    
    

Java Stack 类

栈时 Vector 的一个子类, 它实现了一个标准的后进先出的栈
堆栈只定义了默认构造函数, 用来创建一个空栈. 堆栈除了包括由 Vector 定义的所有方法, 也定义了自己的一些方法
例子:
    import java.util.*;

    public class StackDemo {static void showpush(Stack st, int a) {st.push(new Integer(a));
          System.out.println("push(" + a + ")");
          System.out.println("stack:" + st);
       }

       static void showpop(Stack st) {System.out.print("pop ->");
          Integer a = (Integer) st.pop();
          System.out.println(a);
          System.out.println("stack:" + st);
       }

       public static void main(String args[]) {Stack st = new Stack();
          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");
          }
       }
    }
    运行结果:
        stack: [ ]
        push(42)
        stack: [42]
        push(66)
        stack: [42, 66]
        push(99)
        stack: [42, 66, 99]
        pop -> 99
        stack: [42, 66]
        pop -> 66
        stack: [42]
        pop -> 42
        stack: [ ]
        pop -> empty stack
        

JAVA Dictionary 类

Dictionary 类是一个抽象类, 用来存储键 / 值对, 作用和 Map 类相似
给出键和值, 你就可以将值存储在 Dictionary 对象中, 一旦该值被存储, 就可以通过它的键来获取它.

Dictionary 类已经过时了. 在实际开发中, 可实现 Map 接口 来获取键 / 值的存储功能

JAVA Map 接口

Map 接口中键和值一一映射. 可通过键来获取值
    给定一个键和一个值,你可以将该值存储在一个 Map 对象. 之后,你可以通过键来访问对应的值。当访问的值不存在的时候,方法就会抛出一个 NoSuchElementException 异常.
    当对象的类型和 Map 里元素类型不兼容的时候,就会抛出一个 ClassCastException 异常。当在不允许使用 Null 对象的 Map 中使用 Null 对象,会抛出一个 NullPointerException 异常。当尝试修改一个只读的 Map 时,会抛出一个 UnsupportedOperationException 异常。方法: https://code.ziqiangxuetang.com/java/java-map-interface.html

例子:
    import java.util.*;

    public class CollectionsDemo {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.print("\t" + m1);
       }
    }
    运行结果:
        Map Elements
            {Mahnaz=31, Ayan=12, Daisy=14, Zara=8}
            

JAVA Hashtable 接口

Hashtable 现在集成到了集合框架中, 支持同步.
Hashtable 在哈希表中存储键 / 值对, 当使用一个哈希表, 要指定用作键的对象, 以及要链接到该键的值

然后, 该键经过哈希处理, 所得到的散列码被用作存储在该表中值的索引

方法:https://code.ziqiangxuetang.com/java/java-hashtable-class.html
例子:
    import java.util.*;

    public class HashTableDemo {public static void main(String args[]) {
          // Create a hash map
          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 1,000 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"));
       }
    }

Java Properties 接口

Properties 继承于 Hashtable. 表示一个持久的属性集. 属性列表中每个键及其对应值都是一个字符串
Properties 类被许多 Java 类使用。例如,在获取环境变量时它就作为 System.getProperties()方法的返回值
方法: https://code.ziqiangxuetang.com/java/java-properties-class.html
例子:
    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 + ".");
       }
    }

正文完
 0