Java路径-03-Java基础语法(java中路径表示方法)

createh52个月前 (01-24)技术教程21

Java标识符

1.1 概念

就是程序员在定义java程序时,自定义的一些名字,例如helloworld 程序里关键字class 后跟的Demo,就是我们定义的类名。类名就属于标识符的一种。 标识符除了应用在类名上,还可以用在变量、函数名、包名上。

1.2 规则

  1. 标识符由26个英文字符大小写(a~zA~Z)、数字(0~9)、下划线(_)和美元符号($)组成。
  2. 不能以数字开头,不能是关键字
  3. 严格区分大小写
  4. 标识符的可以为任意长度

1.3 案例规范

  1. 包名

多个单词组成时所有字母小写(例:package com.itcast)

  1. 类名和接口

多个单词组成时所有单词的首字母大写(例:HelloWorld)

  1. 变量名和函数名

多个单词组成时第一个单词首字母小写,其他单词首字母大写(例:lastAccessTime、getTime)。

  1. 常量名

多个单词组成时,字母全部大写,多个单词之间使用_分隔(例:INTEGER_CACHE)

注意:只是为了增加规范性、可读性而做的一种约定,标识符在定义的时候最好见名知意,提高代码阅读性。

2 Java修饰符

2.1 分类:

  • 访问控制修饰符 : default, public , protected, private
  • 非访问控制修饰符 : final, abstract, static, synchronized

修饰符用来定义类、方法或者变量,通常放在语句的最前端。

2.2 访问控制修饰符

Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

  • default (即缺省,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
  • private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
  • public : 对所有类可见。使用对象:类、接口、变量、方法
  • protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)



2.2.1 默认访问修饰符-不使用任何关键字

使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public。

2.2.2 私有访问修饰符-private

私有访问修饰符是最严格的访问级别,所以被声明为 private 的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为 private。 声明为私有访问类型的变量只能通过类中公共的 getter 方法被外部类访问。 Private 访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。

2.2.3 公有访问修饰符-public

被声明为 public 的类、方法、构造方法和接口能够被任何其他类访问。 如果几个相互访问的 public 类分布在不同的包中,则需要导入相应 public 类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。

Java 程序的 main() 方法必须设置成公有的,否则,Java 解释器将不能运行该类。

2.2.4 受保护的访问修饰符-protected

protected 需要从以下两个点来分析说明:

  • 子类与基类在同一包中:被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问;
  • 子类与基类不在同一包中:那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的protected方法。

protected 可以修饰数据成员,构造方法,方法成员,不能修饰类(内部类除外)

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

子类能访问 protected 修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。

2.2.5 访问控制和继承

请注意以下方法继承的规则:

  • 父类中声明为 public 的方法在子类中也必须为 public。
  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
  • 父类中声明为 private 的方法,不能够被继承。

3.3 非访问修饰符

为了实现一些其他的功能,Java 也提供了许多非访问修饰符。

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

3.3.1 static 修饰符

  • 静态变量: static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。
  • 静态方法: static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。 对类变量和方法的访问可以直接使用 classname.variablenameclassname.methodname 的方式访问。

3.3.2 final 修饰符

  1. final 变量

final 表示"最后的、最终的"含义,变量一旦赋值后,不能被重新赋值。被 final 修饰的实例变量必须显式指定初始值。 final 修饰符通常和 static 修饰符一起使用来创建类常量。

  1. final 方法

类中的 final 方法可以被子类继承,但是不能被子类修改。 声明 final 方法的主要目的是防止该方法的内容被修改。

  1. final 类

final 类不能被继承,没有类能够继承 final 类的任何特性。

3.3.2 abstract 修饰符

  1. 抽象类:

抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。 一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。 抽象类可以包含抽象方法和非抽象方法。

  1. 抽象方法

抽象方法是一种没有任何实现的方法,该方法的的具体实现由子类提供。 抽象方法不能被声明成 final 和 static。 任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。 如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。 抽象方法的声明以分号结尾,例如:public abstract sample();

3.3.3 synchronized 修饰符

synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。

3.3.4 transient 修饰符

序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。 该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。 transient变量不会贯穿对象的序列化和反序列化,生命周期仅存于调用者的内存中而不会写到磁盘里进行持久化。

3.3.5 volatile 修饰符

volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。 一个 volatile 对象引用可能是 null。

4 Java变量

4.1 变量的使用定义

变量用于操作系统中,实体之间的传递,把变量看作一个在内存空间中声明的存储位置,在调用变量的时候,系统会自动的调用内存中的存储位置。 在Java中,变量又称为字段,故字段在Java中又有分类。 变量命名为驼峰输入法:如testWord,textWordOne,testWordTwo...开头首单词大写,后面单词小写。

4.2 变量类别

4.2.1 成员变量定义

成员变量又称为成员字段实例字段。成员变量位于类体(Class)的区域范围内,所以它是属于类的。在Java中创建实例字段后,成员变量也会随之在类体加载完成后进行堆栈(内存区域)的创建。

下面为创建成员变量的语法格式:

class 类体 {

     数据类型  变量名;          //此为创建成员变量的语法格式
}

4.2.2 局部变量定义

局部变量是在方法下的变量,位于方法块的区域内。在方法调用的时候会进行创建局部变量,然后生成相应的空间等待执行调用。

下面为创建局部变量的语法格式:

class 类体 {

     数据类型  变量名;          //此为创建成员变量的语法格式
     public static void main(String [] args) {
         数据类型  变量名;          //此为创建局部变量的语法格式,位于方法中
    }
}  

4.3 变量使用中的分类

变量在使用的过程中也有使用分类的定义。

4.3.1 变量在方法中的使用

变量在方法标签的括号中称为“临时参数”或者“临时变量”。

实例:

class 类体 {

     public  void 方法名 (数据类型 临时变量名) {

        //此为创建方法的临时变量
         System.out.println("输出方法的临时参数:" + 临时变量名);

    }
}  

注: 临时变量的使用范围(生命周期)只能在方法内使用。

4.3.2 变量在类中的使用

变量在类中称为成员变量(成员字段),加上修饰符之后又是另一种定义。

4.3.2.1 static 变量名

static 变量名: static又称为静态的意思,加入成员变量后又称为“静态变量”或者“静态字段”。

如下:

class 类体 {

     static 数据类型  变量名;          //此为创建静态成员变量的语法格式
}  

注:静态变量在创建后会变成类的变量,不在属于通过创建对象调用的变量。

下面为创建静态类中方法的静态局部字段的语法格式:    

static class 类体 {

     static 数据类型  变量名;      //此为创建静态成员变量的语法格式

     public static void main(String [] args) {

         static 数据类型  变量名;     //此为创建方法中的静态局部变量的语法格式,位于方法中
    }
 } 

注:静态变量在方法中的使用,前提是整个方法也是静态的。

4.3.2.2 final 变量名

final 变量名:

final称为最终的意思,故所创建的变量是不变的、恒等的关系存在,所以添加到变量中又称为“最终字段”或“不变的变量”。

创建最终字段的语法格式::

class 类体 {

     final 数据类型  变量名;          //此为创建最终不变成员变量的语法格式
}  

下面为创建类中方法的最终字段的语法格式; 

static class 类体 {

     fianl 数据类型  变量名;          //此为创建静态成员变量的语法格式

     public static void main(String [] args) {

         final 数据类型  变量名;      //此为创建方法中的**最终字段**的语法格式,位于方法中

    }
} 

4.3.2.3 final static 变量名

final static 变量名:

final static 变量名所创建的对象是“最终静态的意思”,故所创建的变量是静态最终不变的存在,所以添加到变量中又称为“常量”或者“最终静态字段”(在创建的时候变量名要求大写,单词之间下划线_隔开,如“TEST_Word”)。

创建常量的语法格式:

class 类体 {

     final static 数据类型  变量名;          //此为创建**常量**的语法格式

}  

4.4 小结

变量总体来说就三种,一种是成员变量,属于类个体的变量;一种是局部变量,属于方法中的变量;一种是临时变量,属于方法中传递参数的变量。 三种变量的使用和说定义都已经给了出来,如何赋值使用请自己尝试吧,加油哟年轻人。 如果上面三种变量弄懂嘞,搞懂了,然后就把下面修饰符所修改的static,final记下来吧,并不要求会用,在你初学的时候这些还是会有所收获的,在_变量中还会涉及到他们的定义范围,适用范围,生命周期等等。

5 Java数组

5.1 数组的定义

  • 数组是相同类型数据的有序集合
  • 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成
  • 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标(编号、标记) 来访问它,下标是从 0 开始的,如果是存 10 个数组,那么下标是从 0 ~ 9
  • 代码举例
public class ArrayDemo01 {
    //变量的类型 变量的名字   =   变量的值
    public static void main(String[] args) {
        int[] nums = {1,2,3,4,5,6,7,8,9,10};
        System.out.println(nums[0]);    //1 打印下标元素为0的内容
    }
}

5.2 数组的声明创建

  • 首先必须声明数组变量,才能在程序中使用数组
    • 语法
dataType[] arrayRefVar;	//首选的方法
dataTypr arrayRefVar[];	//效果相同,但不建议
    • 代码举例
    • //数组类型[] 数组名字;
int[] nums;
int nums[];
  • Java 语言使用 new 操作符来创建数组
    • 语法
dataType[] arrayRefVar = new dataType[srraySise];
    • 代码举例
//数组类型[] 数组名字 = new 数组类型[数组容量];
int[] nums = new int[10]
  • 数组的元素是通过索引访问的,数组索引0 开始
  • 获取数组长度
//数组名字.lengtharrays.length 
//nums.length
  • 代码总结举例
public class ArrayDemo01 {
    //变量的类型 变量的名字   =   变量的值
    public static void main(String[] args) {
        //int[] nums = {1,2,3,4,5,6,7,8,9,10};  //一次性给数组元素赋值
        //System.out.println(nums[0]);    //1
        //2种定义数组方法
        int[] nums; //首选定义方法
        int nums2[]; //第二种定义方法  C语言语法,为了让C语言程序员而兼容。

        //int[] nums = new int[10]; //一步到位定义好存放数组大小
        nums = new int[10]; //这里面可以存放 10 个 int 类型的数字
    
        //依次给数组元素赋值
        nums[0] = 1;
        nums[1] = 2;
        nums[2] = 3;
        nums[3] = 4;
        nums[4] = 5;
        nums[5] = 6;
        nums[6] = 7;
        nums[7] = 8;
        nums[8] = 9;
        nums[9] = 10;
    
        //计算所有元素的和
        int sum = 0;
        //获取数组长度:arrays.length
    
        for (int i = 0; i < nums.length; i++) {
            sum = sum + nums[i];
        }
    
        System.out.println("总和为:" + sum);   //55
    }
}


5.3 数组的内存

  • 数组内存分析



  • 画图分析数组内存


5.4 数组的三种初始化

  1. 静态初始化创建的同时赋值
  2. 代码语法举例
int[] a = {1, 2, 3};    //正常的静态初始化
Man[] mans = {new Man(1, 1), new Man(2, 2)};    //引入的静态初始化
  1. 动态初始化:包含默认初始化,未赋值的元素默认为 0
  2. 代码语法举例
int[] a = new int[3];
a[0] = 1;   
a[1] = 2;
System.out.println(a[0]);   //1
System.out.println(a[1]);   //2
System.out.println(a[3]);   //0     未赋值则为 0     默认初始化
  1. 数组的默认初始化:数组是引用类型,它的元素相当于实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化(0)
  2. 代码语法举例
int[] a = new int[1];
System.out.println(a[1]);   //0     未赋值则为 0

5.5 数组的四个基本特点

  1. 其长度是确定的。数组一旦被创建,它的大小就是不可以改变
  2. 元素必须是相同类型不允许出现混合类型
  3. 数组中的元素可以是任何数据类型,包括基本类型引用类型
  4. 数组变量属于引用类型,数组也可以看成是对象,数组指定每个元素相当于该对象成员变量数组本身就是对象Java对象是在中的,因此数组无论保护原始类型还是其他对象类型数组对象本身是在堆中的

5.6 数组的边界

  • 下标的合法区间[0, length-1],如果越界就会报错 ArrayIndexOutOfBoundsException (数组下标越界异常)
    • 代码举例
public class ArrayDemo02 {
    public static void main(String[] args) {
        //静态初始化:创建的同时赋值
        int[] a = {1, 2, 3, 4, 5, 6, 7, 8};
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
            //正常遍历出 a 这个数组内所有值
        }
        /*
        for (int i = 0; i <= a.length; i++) {   //将 i < a.length 改为 i <= a.length
            System.out.println(a[i]);
            //先报错随后正常遍历出a这个数组内所有值
            //下标为 数组长度 -1,例如 a[0] = 1 而不是 a[1] = 1。当 for 循环走到 i <= a.length 时,下标为 8 (a[8]),a(8)未赋值且超过数组最大长度因此会越界报错
        }
        */
    }
}
  • 结论
    • 数组是相同数据类型 (数据类型可以为任意类型)有序集合
    • 数组也是对象数组元素相当于对象成员变量
    • 数组长度是确定不可改变的越界报错 ArrayIndexOutOfBoundsException (数组下标越界异常)

5.7 数组的使用

  • 普通的 For 循环
public class ArrayDemo03 {
    public static void main(String[] args) {
        int[] arrays = {1, 2, 3, 4, 5};
    
        //打印全部的数组元素
        for (int i = 0; i < arrays.length; i++) {
            System.out.println(arrays[i]);
        }
    
        //计算所有元素的和
        int sum = 0;
        for (int i = 0; i < arrays.length; i++) {
            sum += arrays[i];   //sum = sum + arrays[i]
        }
        System.out.println("sum=" + sum);
    
        //查找最大元素
        int max = arrays[0];
        for (int i = 1; i < arrays.length; i++) {   //arrays[0] 已经是 max 的默认值,因此我们改成 i = 1 ,从 1 开始
            if (arrays[i] > max){
                max = arrays[i];
            }
        }
        System.out.println("max=" + max);
    }
}
  • For-Each 循环
public class ArrayDemo04 {
    public static void main(String[] args) {
        int[] arrays = {1, 2, 3, 4, 5};
            //JDK1.5特性  只遍历全部值,没有下标
        for (int array : arrays) {  //增强型 for 循环,关键字 arrays.for 自动生成
            System.out.println(array);
        }
    }
}
  • 数组作方法入参
public class ArrayDemo04 {
    public static void main(String[] args) {
        int[] arrays = {1, 2, 3, 4, 5};
        //调用打印数组元素方法
        printArray(arrays); //更好的遍历数组,在需要时可以取到下标
    }
    //打印数组元素
    public static void printArray(int[] arrays){    //更好的遍历数组,在需要时可以取到下标
        for (int i = 0; i < arrays.length; i++) {
            System.out.print(arrays[i] + " ");
        }
    }
}
  • 数组作返回值
public class ArrayDemo04 {
    public static void main(String[] args) {
        int[] arrays = {1, 2, 3, 4, 5};
        int[] result = reverse(arrays); //调用反转数组方法
        printArray(result); //更好的遍历数组,在需要时可以取到下标
    }
    
    //打印数组元素
    public static void printArray(int[] arrays){    //更好的遍历数组,在需要时可以取到下标
        for (int i = 0; i < arrays.length; i++) {
            System.out.print(arrays[i] + " ");
        }
    }
    
        //反转数组
    public static int[] reverse(int[] arrays){
        int[] result = new int[arrays.length];  //保证传入的数组不会超出最大长度
    
        //反转的操作
        for (int i = 0, j = result.length-1; i < arrays.length; i++, j--) { //result.length-1 是因为下标从 0 开始而 length 长度是从 1 开始,一次使用两个组合 for 循环
            result[j] = arrays[i];
        }
    
        return result;  //返回值
    }
}

5.8 多维数组

  • 多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一堆数组,其每一个元素都是一个一堆数组
    • 二维数组
      • 语法
int a[][] = new int[2][5];
int[][] a = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
public class ArrayDemo05 {
    public static void main(String[] args) {
        int[][] array = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
        //int array[][] = new int[2][5];    //相当于一个数组内嵌套了 2 层的数组
        /*
        //解析如下:
        a =
        {
            {1, 2}, //2 层嵌套的数组
            {3, 4},
            {5, 6},
            {7, 8},
            {9, 10},
        }
        */
        //打印指定元素的值
        System.out.println(array[0][0]);    //1
        System.out.println(array[0][1]);    //2
        System.out.println(array[1][1]);    //4
        System.out.println(array.length);   //5 5列
        System.out.println(array[0].length);    //2 2行
    }
}

解析:以上二维数组 a 可以看成一个两行五列数组 三维数组 语法

int a[][][] = new int[][][];
int[][][] a = {{{1, 2}, {3, 4}}};

代码举例

public class ArrayDemo05 {
    public static void main(String[] args) {
        int[][][] array = {{{1, 2}, {3, 4}},{{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}};
        //int array[][][] = new int[2][2][3];    //相当于一个数组内嵌套了 3 层的数组
        /*
        //解析如下:
        a =
        {
            {
                {1, 2},
                {3, 4},
            },
            {
                {5, 6},
                {7, 8},
            },
            {
                {9, 10},
                {11, 12},
            },
            //3 层嵌套的数组
        }
        */
        //打印指定元素的值
        System.out.println(array[0][0][0]);    //1
        System.out.println(array[0][0][1]);    //2
        System.out.println(array[1][1][1]);    //8
        System.out.println(array.length);   //3 3组
        System.out.println(array[0].length);    //2 2列
        System.out.println(array[0][1].length); //2 2行
    }
}

解析:以上三维数组 a 可以看成一个两行两列三组数组

  • 遍历多维数组
    • 遍历二维数组代码举例
public class ArrayDemo05 {
    public static void main(String[] args) {
        int[][] array = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
        //遍历
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                System.out.println(array[i][j]);
            }
        }
    }
}

遍历三维数组代码举例

public class ArrayDemo06 {
    public static void main(String[] args) {
        int[][][] array = {{{1, 2}, {3, 4}},{{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}};
                //遍历
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                for (int k = 0; k < array[i][j].length; k++) {
                    System.out.println(array[i][j][k]);
                }
            }
        }
    }
}

5.9 数组的 Arrays 类

  • 调用数组的工具类 java.util.Arrays
import java.util.Arrays;	//调用工具类

public class ArraysDemo07 {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,3554,65,6,231324};  
        Arrays.sort(a);//所有的 Arrays 都需要调用 import java.util.Arrays; 工具类
}
  • 由于数组对象并没有什么方法可以供我们调用,但 API 中提供了一个工具类 Arrays 供我们使用,从而可以对数据对象进行一些基础操作
    • 查看 Arrays 类内所有方法
      • 方法①:打开 JDK 帮助文档(搜索 Arrays)查看


  • Arrays 类中的方法都是 static 修饰的静态方法,在使用的时候可以直接使用类名进行调用,而“不用”使用对象来调用(注意:是“不用”而不是“不能”)
import java.util.Arrays;
    
public class ArraysDemo07 {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,3554,65,6,231324};
            
        //直接调用
        printArray(a);  //[1, 2, 3, 4, 3554, 65, 6, 231324]
    }
        
    //创建方法	使用 static 修饰符
    public static void printArray(int[] a){
        System.out.print("[");
        for (int i = 0; i < a.length; i++) {
            String symbol = "";
            if (i != a.length-1){
                symbol = ", ";
            }else{
                symbol = "";
            }
            System.out.print(a[i] + symbol);
        }
        System.out.println("]");
    }
}
  • 它具有以下常用功能:
    • 打印数组元素:通过 toString 方法直接遍历
import java.util.Arrays;
        
public class ArraysDemo07 {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,3554,65,6,231324};
        
        //打印数组元素:Arrays.tostring
        System.out.println(Arrays.toString(a)); //[1, 2, 3, 4, 3554, 65, 6, 231324]
                
        //了解原理后咱们也可以自己创建方法来实现
        //可以但不建议,大家了解一下就好。不建议重复造轮子!
        printArray(a);  //[1, 2, 3, 4, 3554, 65, 6, 231324]
    }
            
    //创建方法
    public static void printArray(int[] a){
        System.out.print("[");
        for (int i = 0; i < a.length; i++) {
            String symbol = "";
            if (i != a.length-1){
                symbol = ", ";
            }else{
                symbol = "";
            }
            System.out.print(a[i] + symbol);
        }
        System.out.println("]");
    }
}

给数组重新赋值:通过 fill 方法重新填充

import java.util.Arrays;
        
public class ArraysDemo07 {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,3554,65,6,231324};
        
        //数组填充(重新赋值)
        //Arrays.fill(a, 0);  //全部重新赋值为 0
        //System.out.println(Arrays.toString(a)); //[0, 0, 0, 0, 0, 0, 0, 0]
        Arrays.fill(a, 2, 4, 0);    //包括下标为 2 但不包括下标为 4 之间的元素重新赋值为 0
        System.out.println(Arrays.toString(a)); //[1, 2, 0, 0, 3554, 65, 6, 231324]
    }
}

对数组排序:通过 sort 方法,按升序排序

import java.util.Arrays;
        
public class ArraysDemo07 {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,3554,65,6,231324};
        
        Arrays.sort(a);//数组进行排序:升序
        System.out.println(Arrays.toString(a)); //[1, 2, 3, 4, 6, 65, 3554, 231324]
    }
}

比较数组:通过 equals 方法比较数组中元素值是否相等

import java.util.Arrays;
        
public class ArraysDemo07 {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,3554,65,6,231324};
        
        //给数组中的元素值比较是否相等
        int[] b = {0};
        if(Arrays.equals(a, b)) {   //不相等
            System.out.println("相等");
        }else{
            System.out.println("不相等");
        }
        int[] c = {1,2,3,4,3554,65,6,231324};
        if(Arrays.equals(a, c)) {   //相等
            System.out.println("相等");
        }else{
            System.out.println("不相等");
        }
    }
}

查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作

import java.util.Arrays;
        
public class ArraysDemo07 {
    public static void main(String[] args) {
        int[] a = {1,2,3,4,3554,65,6,231324};
        
        //对数组进行二分查找法操作
        Arrays.sort(a); //使用二分查找法的数组必须是有序的
        System.out.println(Arrays.binarySearch(a, 0));  //2     查找元素值 3,找到后返回下标。
        /*
            若未找到元素值则会出现以下情况:
            [1] 搜索值不是数组元素值,大小在所有数组范围内,下标从1开始计数,返回“ - 按顺序插入点的下标”
            [2] 搜索值是数组元素值,下标从0开始计数,返回搜索值的下标
            [3] 搜索值不是数组元素值,且大于数组内所有元素值,返回 – (数组最大长度 + 1)
            [4] 搜索值不是数组元素值,且小于数组内所有元素值,返回 – 1
        */
    }
}

5.10 数组的冒泡排序

  • 冒泡排序无疑是最为出名的排序算法之一 (总共有八大排序)
    • 冒泡排序的步骤 (两两比较)
    • 比较数组中,两个相邻的元素,如果第一个数比第二个数,我们就将它们交换位置
    • 每一次比较,都会产生出一个最大或者最小的数字
    • 下一轮则可以少一次排序
    • 依次循环,直到结束
    • 代码举例
import java.util.Arrays;
        
public class ArrayDemo08 {
    public static void main(String[] args) {
        int[] a = {2,4,2,1,3,5,6,66,77,7,4,0};
        int[] sort = sort(a);   //调用完我们创建的排序方法后返回一个排序后的数组
        System.out.println(Arrays.toString(sort));
    }
            
    //冒泡排序方法
    public static int[] sort(int[] array){
        //临时变量
        int temp = 0;
        
        //外层循环:判断我们这个要走多少次
        for (int i = 0; i < array.length-1; i++) {  //当循环走到最后的下标时无法与下个下标进行比较就会溢出,因此这里需要 array.length-1 预留一个位置进行比较排序
            //内层循环:比较判断两个数,如果第一个数比第二个数大,则交换位置
            for (int j = 0; j < array.length-1-i; j++) {    //每次遍历比较都要排除掉i且给最后下标的元素值预留1个位置,因此需要 array.length-1-i
                if (array[j+1]
  • 冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较,江湖中人尽皆知
  • 我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为 O(n2)
  • 优化代码举例
import java.util.Arrays;
    
public class ArrayDemo08 {
    public static void main(String[] args) {
        int[] a = {2,4,2,1,3,5,6,66,77,7,4,0};
        int[] sort = sort(a);   //调用完我们创建的排序方法后返回一个排序后的数组
        System.out.println(Arrays.toString(sort));
    }
    
    //冒泡排序方法
    public static int[] sort(int[] array){
        //临时变量
        int temp = 0;
    
        //外层循环:判断我们这个要走多少次
        for (int i = 0; i < array.length-1; i++) {  //当循环走到最后的下标时无法与下个下标进行比较就会溢出,因此这里需要 array.length-1 预留一个位置进行比较排序
            boolean flag = false;   //通过 flag 标识减少没有意义的比较
            //内层循环:比较判断两个数,如果第一个数比第二个数大,则交换位置
            for (int j = 0; j < array.length-1-i; j++) {    //每次遍历比较都要排除掉i且给最后下标的元素值预留1个位置,因此需要 array.length-1-i
                if (array[j+1]

5.11 稀疏数组

  • 稀疏数组的介绍
    • 当一个数组中大部分元素为 0,或者为同一数值的数组时,可以使用稀疏数组来保存该数组
    • 稀疏数组的处理方式
      • 记录数组一共有几行几列,有多少个不同值
      • 把具有不同值元素行列以及记录在一个小规模的数组中,从而缩小程序的规模
    • 如下图 (左边是原始数组,右边是稀疏数组)



下标 0稀疏数组记录整个数组有 6 行 7 列 8 个不为 0 的有效值 下标 1~8稀疏数组:记录每个有效值的位置。例如下标 1 中的 22 ,在数组中,下标从 0 开始计数,那么在稀疏数组中记录为 0 3 22,即为在下标为 0 的行,下标为 3 的列,记录值为 22

  • 稀疏数组的应用
    • 要求:编写五子棋游戏中,有存盘退出和续上盘的功能



问题分析:因为该二维数组的很多值是默认值 0,因此记录了很多没有意义的数据

解决方法稀疏数组

代码举例

public class ArrayDemo09 {
    public static void main(String[] args) {
        //1.创建一个二维数组 11*11(11行11列)      0:没有棋子      1:黑棋        2:白棋
        int[][] array1 = new int[11][11];
        array1[1][2] = 1;   //黑棋位于2行3列(数组从 0 计数)
        array1[2][3] = 2;   //白棋位于3行4列(数字从 0 计数)
        //输出原始的数组
        System.out.println("输出原始的数组");
        for (int[] ints : array1) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
        //转换为稀疏数组来保存
        //1. 获取有效值的个数
        int sum = 0;
        for (int i = 0; i < array1.length; i++) {   //array1.length 取二维数组嵌套的数组个数    11行
            for (int j = 0; j < array1[i].length; j++) {    //array1[0].length 取遍历下标 i 的子数组中值的个数    11列
                if (array1[i][j] != 0){
                    sum++;
                }
            }
        }
        System.out.println("有效值的个数:" + sum);
        //2. 创建一个稀疏数组
        int[][] array2 = new int[sum+1][3]; 
        //之所以行数为有效值个数加 1 是因为需要多加 1 行记录行总数、列总数、有效值个数。固定 3 列
        //多出来的 1 行用用以下代码赋值记录行总数、列总数、有效值个数
        array2[0][0] = 11;
        array2[0][1] = 11;
        array2[0][2] = sum;
        //遍历二维数组,将非零的值(有效值),存放在稀疏数组中
        int count = 0;
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                if (array1[i][j] != 0){
                    count++;    //行递增
                    //利用行递增给稀疏数组赋值记录
                    array2[count][0] = i;
                    array2[count][1] = j;
                    array2[count][2] = array1[i][j];
                }
            }
        }
        //3. 输出稀疏数组
        System.out.println("稀疏数组");
        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i][0] + "\t" + array2[i][1] + "\t" + array2[i][2]);
        }
        //数组还原归位
        //1. 读取稀疏数组
        int[][] array3 = new int[array2[0][0]][array2[0][1]];   //根据数组默认初始化,至此一行代码已还原所有 0 值归为
        //2. 给其中的元素还原它的值
        for (int i = 1; i < array2.length; i++) {   //还原过程中,头部记录的综合信息不需要读取,因此 i=1,从下标 1 开始
            array3[array2[i][0]][array2[i][1]] = array2[i][2];  //在已记录的有效值位置还原有效值
        }
        //3. 打印
        System.out.println("打印还原的数组");
        for (int[] ints : array3) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
    }
}



6 Java枚举

6.1 枚举概述

枚举:列举,一个一个地列出来。 Java枚举:把某个类型的对象,全部列出来。

  • 什么情况下会用到枚举类型?

某些类的对象只有确定的有限个时,可以把这样的类声明为枚举。

例如:

星期:Monday(星期一)......Sunday(星期天)

性别:Male(男)、Female(女)

月份:January(1月)......December(12月)

季节:Spring(春天)......Winter(冬天)

  • 枚举是一种特殊的类,特殊在它的对象是有限的几个常量对象。它既是一种类(class)类型却又比类类型多了些特殊的约束,枚举的本质是一种受限制的类。

当需要定义一组常量时,可以使用枚举。

6.2 枚举类型的定义

枚举是JDK1.5新增的引用数据类型。

  • 枚举的对象的属性不应允许被改动,所以应该使用 private final 修饰
  • 属性应该在构造器中为其赋值
  • 若枚举显式的定义了带参数的构造器,则在列出枚举值时也必须对应地传入参数
  • 枚举的实现:
    • jdk1.5之前,自定义枚举类
    • jdk1.5,可以使用 enum 关键字定义枚举

6.2.1 自定义枚举类

  • 要求:
    • 私有化类的构造器,保证不能在类的外部创建其对象
    • 在类的内部创建枚举类的实例,并用声明为 public static final 的变量来引用
    • 对象如果有实例变量,应该声明为private final,并在构造器中初始化
class Season {
    //声明Season对象的属性:使用 private final 修饰
    private final String seasonName;
    private final String seasonDesc;

    //私有化Season类的构造器,并给对象属性赋值
    private Season(String seasonName, String seasonDesc) {
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    //在类的内部创建当前枚举类的对象,变量用 public static final 修饰
    //public:外部可以使用枚举类的实例
    //static:外部可以使用“类名.对象名”调用
    //final:修饰的变量只能指向一个对象,保存的地址值不能更改
    public static final Season SPRING = new Season("春天", "春暖花开");
    public static final Season SUMMER = new Season("夏天", "烈日炎炎");
    public static final Season AUTUMN = new Season("秋天", "秋高气爽");
    public static final Season WINTER = new Season("冬天", "白雪皑皑");

    //其他需求
    //获取枚举类的对象的属性
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }
    
    //提供toString()
    @Override
    public String toString() {
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
}

public class SeasonTest {
    public static void main(String[] args) {
        Season spring = Season.SPRING;
        System.out.println(spring.getSeasonName());
        System.out.println(spring);
    }
}

2.2 使用enum定义枚举

jdk1.5之前,枚举的定义格式太繁琐,存在很多重复代码 使用 enum 关键字简化枚举的定义

  • 声明格式:
[修饰符] enmu 枚举名{
  //实例列表
  //其他成员列表
}

枚举的所有实例必须在其他成员的前面显式列出(多个实例之间 , 分隔 ; 结尾,只存在实例列表时,最后一个实例后面的 ; 可省略,存在其他成员时,不能省略),它们实际上都是 public static final 修饰的常量对象,不用自己添加修饰符,填上反而会报错。

枚举的所有构造器只能使用 private 访问控制符,并且是隐式私有的。

switch 表达式的case 子句可以直接使用 Enum定义的枚举的对象的名字。

如果枚举中只有一个对象,则可以作为单例模式的一种实现方式。

//RED、GREEN、BLUE不是枚举Color的属性,而是它的对象
enum Color {
    //只有对象列表,可省略最后一个对象后的;
    //对象后面没有“(参数列表)”就是调用无参构造
    RED, GREEN, BLUE
}

//SPRING、SUMMER、AUTUMN、WINTER就是枚举Season的对象
enum Season {
    //对象列表必须写在类的前面,多个对象之间用,隔开,末尾对象;结束
    //对象后面有“(参数列表)”就是调用有参构造
    SPRING("春天", "春暖花开"),
    SUMMER("夏天", "烈日炎炎"),
    AUTUMN("秋天", "秋高气爽"),
    WINTER("冬天", "白雪皑皑"); 

    //声明Season对象的属性:使用 private final 修饰
    private final String seasonDesc;
    private final String seasonName;

    //私有化Season类的构造器,并给对象属性赋值
    private Season(String seasonName, String seasonDesc) {
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    //其他需求
    //获取枚举的对象的属性
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }

    //一般不用重写toString
}

public class SeasonTest {
    public static void main(String[] args) {
        Color blue = Color.BLUE;
        System.out.println(blue); //BLUE
        System.out.println(Color.class.getSuperclass()); //class java.lang.Enum

        Season summer = Season.SUMMER;
        System.out.println(summer); //SUMMER
        System.out.println(Season.class.getSuperclass()); //class java.lang.Enum
        
        Season s = Season.SPRING;
        switch(s) {
            case SPRING:
                System.out.println("春暖花开");
                break;
            case SUMMER:
                System.out.println("烈日炎炎");
                break;
            case AUTUMN:
                System.out.println("秋高气爽");
                break;
            case WINTER:
                System.out.println("白雪皑皑");
                break;
        }
    }
}

6.3 枚举的隐含直接父类:Enum类

枚举不能继承其他类型,因为枚举类型有一个隐含的直接父类 java.lang.Enum :它是所有枚举的父类。

public abstract class Enum>
        implements Comparable, Serializable {...}

Enum类中有一个唯一的构造器:protected Enum(String name, int ordinal)

这个构造器不是程序员手动调用的,是编译器自动调用,在所有枚举类型的构造器的首行,并且自动传入name和ordinal的值。

name:就是枚举对象名称

ordinal:就是枚举对象的序号(在枚举声明中的位置),其中初始常量序号为0

6.3.1 Enum类的主要方法

除了toString方法,都是final修饰的方法,因此都不能重写。

toString():返回此枚举常量的名称,与其在枚举声明中的声明完全相同

String name():返回此枚举常量的名称,与其在枚举声明中的声明完全相同,一般用toString()

int ordinal():返回此枚举常量的序号(在枚举声明中的位置),其中初始常量序号为0

  • API中没有的方法,是编译器帮我们生成的方法:

values()方法:返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值。

valueOf(String str):根据枚举常量的名称返回对应的枚举对象。要求字符串必须是枚举对象的“名字”。如不是,会有运行时异常

//便利枚举的对象
Season[] seasons = Season.values();
for (Season season : seasons) {
    System.out.println(season);
}
//SPRING
//SUMMER
//AUTUMN
//WINTER

Season spring = Season.valueOf("SPRING");
System.out.println(spring); //SPRING

6.4 枚举实现接口

和普通 Java 类一样,枚举也可以实现一个或多个接口。

若每个枚举值在调用实现的接口方法呈现相同的行为,则只要统一实现该方法即可。

若需要每个枚举值在调用实现的接口方法呈现出不同的行为,则可以让每个枚举值分别来实现该方法。

定义接口:

interface MyInter {
   void message();
}

interface Info {
    void show();
}

枚举实现接口:

enum Season implements MyInter, Info {
    SPRING("春天", "春暖花开") {
        @Override
        public void show() {
            System.out.println("春天在哪里");
        }
    },
    SUMMER("夏天", "烈日炎炎") {
        @Override
        public void show() {
            System.out.println("夏天的风");
        }
    },
    AUTUMN("秋天", "秋高气爽") {
        @Override
        public void show() {
            System.out.println("秋天不回来");
        }
    },
    WINTER("冬天", "白雪皑皑") {
        @Override
        public void show() {
            System.out.println("大约在冬季");
        }
    };

    private final String seasonDesc;
    private final String seasonName;

    private Season(String seasonName, String seasonDesc) {
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    //统一实现的重写方法
    @Override
    public void message() {
        System.out.println("一年四季各不同");
    }
}

测试类:

public class SeasonTest {
    public static void main(String[] args) {
        Season spring = Season.SPRING;
        spring.message();
        Season summer = Season.SUMMER;
        summer.message();
        Season autumn = Season.AUTUMN;
        autumn.show();
        Season winter = Season.WINTER;
        winter.show();
    }
}
一年四季各不同
一年四季各不同
秋天不回来
大约在冬季

对于同一个方法,两种重写方式可任选其一,也可同时存在。分别重写时,所有的实例都要自己重写接口中的方法,否则必须添加枚举的统一重写方法。同时存在时,实例自己的重写方法会覆盖枚举的统一重写方法。

枚举既可以包含具体方法,也可以包含抽象方法。 如果枚举含有抽象方法,则枚举的每个实例都必须分别实现该方法。与实现接口类似。

6.5 枚举的应用

6.5.1 在 switch 中使用枚举类

枚举类常应用于 switch 语句中:

enum Color
{
  RED, GREEN, BLUE;
}
public class MyClass {
 public static void main(String[] args) {
  Color myVar = Color.BLUE;

  switch(myVar) {
   case RED:
    System.out.println("红色");
    break;
   case GREEN:
     System.out.println("绿色");
    break;
   case BLUE:
    System.out.println("蓝色");
    break;
  }
 }
}

6.5.2 实现接口,消除 if/else

我们创建的枚举类默认是被final修饰,并且默认继承了Enum类。因此不能再继承其他的类。但是可以去实现接口。

有这样一个判断场景。

if ("dog".equals(animalType)){
    System.out.println("吃骨头");
} else if ("cat".equals(animalType)) {
    System.out.println("吃鱼干");
} else if ("sheep") {
    System.out.println("吃草");
}

怎样用枚举来消除掉 if/else 呐,看下面的代码:

先定义一个接口,里面有一个通用方法 eat()

public interface Eat {
    //吃
    String eat();
}

然后创建枚举类实现这个接口

public enum AnimalEnum implements Eat {
 
    Dog(){
        @Override
        public void eat() {
            System.out.println("吃骨头");
        }
    },
 
    Cat() {
        @Override
        public void eat() {
            System.out.println("吃鱼干");
        }
    },
 
    Sheep() {
        @Override
        public void eat() {
            System.out.println("吃草");
        }
    }
 
}

调用的时候只需要一行代码:

public class Test {
    public static void main(String[] args) {
        AnimalEnum.valueOf("Cat").eat(); // 吃鱼干
    }
}

而且这样一来,以后假如我想扩充新的动物,只需要去枚举类中加代码即可,而不用改任何老代码,符合开闭原则!

6.5.3 枚举类中定义抽象方法

枚举类除了可以实现接口外,还可以在枚举类中定义抽象方法,这样每个枚举的对象只要分别实现了此抽象方法即可。

enum Color{
    RED{
        public String getColor(){//枚举对象实现抽象方法
            return "红色";
        }
    },
    GREEN{
        public String getColor(){//枚举对象实现抽象方法
            return "绿色";
        }
    },
    BLUE{
        public String getColor(){//枚举对象实现抽象方法
            return "蓝色";
        }
    };
    public abstract String getColor();//定义抽象方法
}


public class Test{
    public static void main(String[] args) {
        for (Color c:Color.values()){
            System.out.print(c.getColor() + "、");
        }
    }
}

6.5.4 单例模式中应用

枚举在单例模式的一种实现方式中也可以用到。

/**
 * @Description: 枚举  线程安全
 */
public class SingletonExample {
 
    /**
     * 构造函数私有化,避免外部创建实例
     */
    private SingletonExample(){}
 
    private static SingletonExample getInstance() {
        return Singleton.INSTANCE.getInstance();
    }
 
    private enum Singleton {
        INSTANCE;
        private SingletonExample instance;
 
        // JVM 保证这个方法绝对只调用一次
        Singleton() {
            instance = new SingletonExample();
        }
 
        public SingletonExample getInstance() {
            return instance;
        }
    }
}

7 Java关键字

7.1 关键字

Java关键字是电脑语言里事先定义的,有特别意义的标识符,有时又叫保留字,还有特别意义的变量。Java的关键字对Java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等,关键字不能用作变量名、方法名、类名、包名和参数。



在Java中目前一共有53个关键字:其中由51+2个保留字=53个关键字。

48个关键字:abstract、assert、boolean、break、byte、case、catch、char、class、continue、default、do、double、else、enum、extends、final、finally、float、for、if、implements、import、int、interface、instanceof、long、native、new、package、private、protected、public、return、short、static、strictfp、super、switch、synchronized、this、throw、throws、transient、try、void、volatile、while。

3个特殊直接量:true、false、null。

2个保留字:goto、const。

7.1 关键字说明

【访问控制】

private:私用模式,访问控制修饰符,可以应用于类、方法或字段(在类中声明的变量);

protected:保护模式,可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符;

public:共用模式,可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符。

【类、方法和变量修饰符】

abstract:表明类或者成员方法具有抽象属性,用于修改类或方法;

class:声明一个类,用来声明新的Java类;

extends:表明一个类型是另一个类型的子类型。对于类,可以是另一个类或者抽象类;对于接口,可以是另一个接口;

final:用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量;

implements:表明一个类实现了给定的接口;

interface:接口;

native:用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的;

new:用来创建新实例对象;

static:表明具有静态属性;

strictfp:用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范;

synchronized:表明一段代码需要同步执行;

transient:声明不用序列化的成员域;

volatile:表明两个或者多个变量必须同步地发生变化。

【程序控制】

break:提前跳出一个块;

continue:回到一个块的开始处;

return:从成员方法中返回数据;

do:用在do-while循环结构中;

while:用在循环结构中;

if:条件语句的引导词;

else:用在条件语句中,表明当条件不成立时的分支;

for:一种循环结构的引导词;

instanceof:用来测试一个对象是否是指定类型的实例对象;

switch:分支语句结构的引导词;

case:用在switch语句之中,表示其中的一个分支;

default:默认,例如:用在switch语句中,表明一个默认的分支Java8 中也作用于声明接口函数的默认实现。

【错误处理】

try:尝试一个可能抛出异常的程序块;

catch:用在异常处理中,用来捕捉异常;

throw:抛出一个异常;

throws:声明在当前定义的成员方法中所有需要抛出的异常。

【包相关】

import:表明要访问指定的类或包;

package:包。

【基本类型】

boolean:基本数据类型之一,声明布尔类型的关键字;

byte:基本数据类型之一,字节类型;

char:基本数据类型之一,字符类型;

double:基本数据类型之一,双精度浮点数类型;

float:基本数据类型之一,单精度浮点数类型;

int:基本数据类型之一,整数类型;

long:基本数据类型之一,长整数类型;

short:基本数据类型之一,短整数类型;

null:空,表示无值,不能将null赋给原始类型(byte、short、int、long、char、float、double、boolean)变量;

true:真,boolean变量的两个合法值中的一个;

false:假,boolean变量的两个合法值之一。

【变量引用】

super:表明当前对象的父类型的引用或者父类型的构造方法;

this:指向当前实例对象的引用,用于引用当前实例;

void:声明当前成员方法没有返回值,void可以用作方法的返回类型,以指示该方法不返回值。

【保留字】

goto:保留关键字,没有具体含义;

Const:保留关键字,没有具体含义,是一个类型修饰符,使用const声明的对象不能更新。

8 Java注释

有三种注释:单行注释,多行注释与文档注释

  • 单行注释: //,最常用的注释其注释内容从 // 开始到本行结尾。
  • 多行注释 从 /* 开始直至第一个 */ 出现都属于多行注释,但多行注释不能嵌套,多行注释也可以注释掉不需要的代码
  • 文档注释 可以自动地生成文档,这种注释以 /** 开始,以 */ 结束

8.1 单行注释与多行注释

/**
 * 这就是传说中的文档注释
 * @author 作者
 * 可以自动生成文档
 */
public class Hello{
    public static void main(String[] args){
         //这是单行注释
	    System.out.println("你好");
	    /*
	    System.out.println("你好");
	    System.out.println("你好");
	    这里都是多行注释
	    */
     }
}

8.2 文档注释

使用文档注释/** */,文档注释一般用于对类和方法进行功能说明 ,说明类的编写时间和作者以及方法作用参数和返回值

8.2.1 类上的注释

/** 
 * 类上的文档注释 
 * @author 张三 * 
 * @version 1.10.0 
 **/

8.2.2 方法上的注释

/** 
 * 方法前的文档注释 
 * @param 
 * @return 
 * @throws 
 **/

8.2.3 注释标签

标签

描述

示例

@author

标识一个类的作者

@author description

@deprecated

指名一个过期的类或成员

@deprecated description

{@docRoot}

指明当前文档根目录的路径

Directory Path

@exception

标志一个类抛出的异常

@exception exception-name explanation

{@inheritDoc}

从直接父类继承的注释

Inherits a comment from the immediate surperclass.

{@link}

插入一个到另一个主题的链接

{@link name text}

{@linkplain}

插入一个到另一个主题的链接,但是该链接显示纯文本字体

Inserts an in-line link to another topic.

@param

说明一个方法的参数

@param parameter-name explanation

@return

说明返回值类型

@return explanation

@see

指定一个到另一个主题的链接

@see anchor

@serial

说明一个序列化属性

@serial description

@serialData

说明通过writeObject( ) 和 writeExternal( )方法写的数据

@serialData description

@serialField

说明一个ObjectStreamField组件

@serialField name type description

@since

标记当引入一个特定的变化时

@since release

@throws

和 @exception标签一样.

The @throws tag has the same meaning as the @exception tag.

{@value}

显示常量的值,该常量必须是static属性。

Displays the value of a constant, which must be a static field.

@version

指定类的版本

@version info

9 继承

9.1 继承概述

继承是面向对象的三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,追加属性和方法。

  • 继承是指在原有类的基础上,进行功能扩展,创建新的类型。
  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
  • JAVA中类只有单继承,没有多继承!
  • 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
  • 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
  • 子类和父类之间,从意义上讲应该具有"is a"的关系。
  • extends的意思是“扩展”,子类是父类的扩展。

继承的格式:

  • 格式: public class 子类名 extends 父类名{}
  • 例如: public class Zi extends Fu {}
  • Fu:是父类,也被称为基类、超类
  • Zi: 是子类,也被称为派生类

继承中子类的特点:

  • 子类可以有父类的内容,子类还可以有自己特有的内容。

9.2 继承的优缺点

继承好处:

  • 实现了数据和方法的共享
  • 提高了代码的复用性(多个类相同的成员可以放到同一个类中)
  • 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)
  • 提高了代码的可扩展性

继承弊端:

  • 继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟看变化,削弱了子类的独立性

9.3 继承中变量的访问特点

在子类方法中访问一个变量

  • 最先在子类局部范围找,如果没有就在子类成员范围找,最后在父类成员范围找,如果都没有就报错(不考虑父亲的父亲...)。

9.4 super

super 关键字的用法和 this 关键字的用法相似

  • this:代表本类对象的引用(this关键字指向调用该方法的对象一般我们是在当前类中使用this关键字所以我们常说this代表本类对象的引用)
  • super:代表父类存储空间的标识(可以理解为父类对象引用)



9.5 继承中构造方法的访问特点

子类中所有的构造方法默认都会访问父类中无参的构造方法。

  • 因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化
  • 每一个子类构造方法的第一条语句默认都是: super()

如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?

  • 通过使用super关键字去显示的调用父类的带参构造方法
  • 在父类中自己提供一个无参构造方法
  • 推荐: 自己给出无参构造方法

9.6 继承中成员方法的访问特点

通过子类对象访问一个方法:

  • 先子类成员范围找,如果找不到就在父类成员范围找,如果都没有就报错(不考虑父亲的父亲...)

9.7 方法重写

  • 方法重写概述:子类中出现了和父类中一模一样的方法声明
  • 方法重写的应用:当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
  • @Override: 是一个注解可以帮助我们检查重写方法的方法声明的正确性

9.8 方法重写的注意事项

  • 私有方法不能被重写(父类私有成员子类是不能继承的)
  • 子类方法访问权限不能更低(public>默认>私有)

9.9 java中继承的注意事项

  • Java中类只支持单继承,不支持多继承
  • Java中类支持多层继承

10 接口

接口与抽象类相比,使用率是最高的,所有的设计基本是围绕接口进行的,这部分内容很重要,要彻底学明白需要很长时间,与接口相关 的两个重要设计模式:工厂设计模式、代理设计模式,是需要死记硬背的。

10.1 接口的基本概念

接口是一种特殊类,但是接口中的组成比类的简单,主要由抽象方法和全局常量组成。而接口使用interface关键字来定义。

【举例】:定义一个接口

interface A{ //定义了一个接口
    public static final String MSG= "hello";
    public abstract void print();
}

接口是不能直接实例化对象的,当一个接口定义完成后,按如下步骤进行接口的使用:

  • 1)接口一定要定义子类,子类利用implements关键字来实现接口,一个子类可以实现多个接口;
  • --秒杀抽象类的单继承局限;
  • 2)接口的子类必须覆写接口中的全部抽象方法;
  • 3)接口的对象利用子类对象的向上转型进行实例化操作。

【举例】:使用接口

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        X x = new X();//实例化子类对象
        A a = x;   //子类为父接口实例化
        B b = x;
        a.print();
        b.fun();
    }
}

interface A{ //定义了一个接口
    public static final String MSG= "hello";
    public abstract void print();
}
interface B{
    public abstract void fun();
}
class X implements A,B{//同时实现A、B两个父接口

    @Override
    public void print() { //覆写接口A中的抽象方法
        System.out.println("你好,接口A");
    }

    @Override
    public void fun() {//覆写接口B中的抽象方法
        System.out.println(MSG);
    }
}



但是,现在有这样一种操作,也能输出hello,B和A没有什么关系,却可以转换,因为X是子类。

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        A a = new X();   //X子类为父接A口实例化
        B b = (B)a;
        b.fun();
    }
}

【注意】:关于接口的组成描述

接口里面在定义的时候就已经明确的给出了开发要求:抽象方法和全局常量,所以,以下两种接口的定义本质上是一样的。

完整定义

简化定义

interface A{ //定义了一个接口 public static final String MSG= "hello"; public abstract void print(); }

interface A{ //定义了一个接口 String MSG= "hello"; void print(); }

如果定义接口方法时没有使用public,本质上也不是default权限,默认就是public。为了防止开发者概念混淆,所以后续开发建议在定义接口时都写上public,可以不写abstract。

interface A{ //定义了一个接口
     String MSG= "hello";
     public void print();
}

现在程序中出现有类、抽象类、接口,三者之间的联系需要注意:

一个普通类若要实现接口,又要继承抽象类,一定要显extends继承抽象类,再实现接口,形式如下:

class 子类 extends 抽象类 implements 接口1,接口2,...{}

【举例】:观察子类的多继承

interface A{ //定义了一个接口
    public static final String MSG= "hello";
    public abstract void print();
}
abstract class B{
    public abstract void fun();
}

class X extends B implements A{
    @Override
    public void print() {
    }
    @Override
    public void fun() {
    }
}

另外,除了以上的结构外,抽象类还可以直接实现接口:

【举例】:抽象类实现接口

interface A{ //定义了一个接口
    public static final String MSG= "hello";
    public abstract void print();
}
abstract class B implements A{ //此时抽象类有两个抽象方法
    public abstract void fun();
}

class X extends B{
    @Override
    public void print() {
    }
    @Override
    public void fun() {
    }
}

抽象类可以实现接口,但是反过来,接口是不能继承抽象类的,一个接口却可以使用extends关键字继承多个父接口。

【举例】:接口多继承

interface A{ //定义了一个接口
    public void printA();
}
interface B{
    public void printB();
}
interface C extends A,B{ //C是A与B 的子接口
    public void printC();
}
class X implements C{
    @Override
    public void printA() {
    }
    @Override
    public void printB() {
    }
    @Override
    public void printC() {
    }
}

虽然接口本身只能有抽象方法 和全局常量,但是内部的结构是不受限制 的,也就是 一个接口的内部可以继续定义内部类,内部抽象类,或内部接口。如果一个内部接口上使用了static定义,这个内部接口就属于外部接口。

【举例】:使用static定义内部接口

interface A{ //定义了一个接口
    static interface B{
        public void print();
    }
}
class X implements A.B{//注意此处使用的是.........
    @Override
    public void print() {
    }
}

对于接口的使用,有如下几点总结:

  • 接口避免了单继承局限,一个子类可以实现多个接口;
  • 接口中 的权限统一为public,方法都是抽象方法,大多数情况下接口中都不会定义全局常量;
  • 所有的内部类结构都不受定义语法的限制,static定义的内部接口就是外部接口。

实际开发中,接口的三个使用原则:

  • 制定操作的标准;
  • 表示一种能力;
  • 将服务器端的远程方法视图提供给客户端。

10.2 接口的应用

  • 标准(连接不同的两种类)
  • 工厂设计模式
  • 代理设计模式。
  • ……

11 Java源码

相关文章

Java标识符和关键字有哪些?(java标识符和关键字有哪些区别)

在编写Java程序时,我们常常需要为类、变量、方法等命名。这些名称在Java中被称为标识符。标识符是开发者自定义的,用来表示各种程序元素。与此相对,有一些名称被Java语言赋予了特定的含义,只能用于特...

Java语言的标识符(JAVA语言的标识符是区分大小写的)

Java语言的标识符:对类名、属性名、方法名、变量名等要素的命名使用称之为标识符(英文:identifier)。Java中对标识符的规定:标识符可以由26个字母、数字、下划线`_`、特殊符号`$`所组...

Java中的关系运算符(java的关联关系)

5.1运算符的介绍运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等5.2算术运算符5.2.1介绍算术运算符是对数值类型的变量进行运算的。5.2.2算术运算符分类运算符运算范例结果+正号+55-...

标识符是什么(产品标识符是什么)

标识符是用来给变量、类、方法以及包进行命名的,如 Welcome、main、System、age、name、gender 等。标识符需要遵守一定的规则:1、标识符必须以字母、下划线_、美元符号$开头。...

「书讯」面向对象程序设计(Java)(面向对象程序设计教程)

《面向对象程序设计(Java)》作者:李建勋,郭建华,佟瑞 著出版日期:2021年4月开本:16开出版社:经济管理出版社小编推荐面向对象程序设计是一种接近人类思维活动的计算机软件程序设计思想,其具备...

java 9 集合工厂方法:快速创建只读集合和“标识符优化”

新增的方法调用集合中静态方法 of(),可以将不同数量的参数传输到此工厂方法中。此功能可用于 Set 和 List,也 可用于 Map 的类似形式。此时得到 的集合,是不可变的:List.ofSet....