Java学习之旅【个人笔记/已完结】

以后工作想向 Java Web 发展,有很多需要学习的。但是已经很久很久没有摸过Java了,那就从Java复习开始吧。目前跟着狂神进行一个学习,写写笔记给自己记录一下吧。
(翻了翻先前的笔记才发现我竟然也是学过Java的人诶!)

一、基础部分

基础知识几乎所有语言通用,也都还记得些,就整一些自己可能会忘记的。

1.基本数据类型

//整数
int num1 = 10;
byte num2 = 20;
short num3 = 30;
long num4 = 40L;    //long类型要在数字后加个L

//小数
float num5 = 50.1F;     //float类型要在数字后加个F
double num6 = 3.1415926;

//字符
char name1 = 'a';
String name2 = "张三";    //String不是关键字,是类

//布尔值,只有true和false
boolean flag1 = true;
boolean flag2 = false;

2.常量与变量

常量用 final 修饰;
变量有三种:类变量、实例变量、局部变量。

public class Main {
    
    //常量 final:为修饰符,不存在先后顺序
    //即 static 和 final 位置可互换
    static final double PI = 3.14;

    //实例变量:从属于对象;若不进行初始化,则为默认值
    String name;
    int age;
    boolean flag;
    
    //类变量 static
    static double salary = 2500;
    
    //main方法
    public static void main(String[] args) {

        //常量
        System.out.println(PI);

        //局部变量:在main方法里,使用前必须声明和初始化
        String str = "Hello World";
        System.out.println(str);    //局部变量定义了就能用

        //实例变量:变量类型 变量名字 = new ActionScope();
        ActionScope actionScope = new ActionScope();
        System.out.println(actionScope.age);
        System.out.println(actionScope.name);
        System.out.println(actionScope.flag);

        //类变量 static
        System.out.println(salary);
    }

    //其他方法
    public void other() {

    }
}

3.移位运算符

直接与计算机底层打交道,效率极高
例如:计算 2^3,即 2 * 2 * 2。计算机通过将 0000 0010 (二进制)左移3位,得到 0001 0000(二进制),即算得结果为16(十进制)。

public class Main {
    public static void main(String[] args) {
        /*
        A = 0011 1100
        B = 0000 1101
        ---------------------------------
        A & B = 0000 1100
        A | B = 0011 1101
        A ^ B = 0011 0001
        ~ B = 1111 0010
        ---------------------------------
        << 左移
        >> 右移
         */
        System.out.println(2<<3);
        System.out.println(14>>2);
    }
}

第一个输出结果为16不再做解释,第二个输出为3。
14(十进制)= 0000 1110
右移两位后:0000 0011
最后一个1超出边界了,不要它了!所以转换为十进制后得到结果为3。

二、流程控制

一些流程控制,条件分支、循环等等,也仅仅记录一些自己会遗忘的。

1. next ( ) 与 nextLine ( )

next ( ):以空格和回车为结束标志。例:输入Hello World,输出为Hello。
nextLine ( ):仅以回车为结束标志。例:输入Hello World,输出为Hello World。

2.switch

JDK7之后支持String类型的比较了

记录switch是因为在idea上发现了一些好玩的东西,先前用eclipse时没有提示。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String grade = scanner.nextLine();

        switch (grade) {
            case "A" -> System.out.println("优秀");
            case "B" -> System.out.println("良好");
            case "C" -> System.out.println("及格");
            case "D" -> System.out.println("不及格");
            default -> System.out.println("未知等级");
        }

        scanner.close();
    }
}

3.关于For循环的一道例题

代码本身比较简单,学到了点新的操作:输出1000.for,idea会自动生成for语句,上下界记得自行修改。

用for循环输出1-1000之内能被5整除的数,并且每行输出3个。

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i <= 1000; i++) {
            if(i % 5 == 0)
                System.out.print(i + "\t");
            //每行输出三个数字,即查找15个数字后换行
            if(i % 15 == 0)
                System.out.print("\n");
        }
    }
}

4.打印三角形

这题的思想特别妙,是从未设想过的道路,进行一个记录。

public class Main {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            for (int j = 5; j >= i; j--)   //打印上三角的空白部分
                System.out.print(" ");
            for (int j = 1; j <= i; j++)    //打印左半个三角形
                System.out.print("*");
            for (int j = 1; j < i; j++)     //打印右半个三角形
                System.out.print("*");

            System.out.println();
        }
    }
}

运行结果:

    *
   ***  
  ***** 
 *******  
*********

三、方法

方法类似于C中的函数,写在类中,先前我们写的代码都是在main方法中的。自己编写新方法时,应与main方法保持并列的关系。注:Java都是值传递!
要开始认真学习了!先前学习的时候就有些一知半解。

1.简单加法

public class Main {
    //main方法
    public static void main(String[] args) {
        int sum = add(1,2);
        System.out.println(sum);
    }

    //加法,加static修饰后成为类变量,方便在主函数中调用
    //后续学了对象之后再调整
    public static int add(int a, int b){
        return a + b;
    }
}

2.比较大小

public class Main {
    public static void main(String[] args) {
        int max = compare(10, 10);
        System.out.println(max);
    }

    //比较大小
    public static int compare(int a, int b){
        int result = -1;    //建议将result初始化赋值,随便什么都可以
        if(a == b)
            return 0;   //终止方法
        if(a > b)
            result = a;
        else
            result = b;
        return result;
        /*
        一般而言,return写在最后,
        if(xxx)     return xxx;
        else        return xxx;
        该写法不推荐!
         */
    }
}

3.方法的重载

重载:在一个类中,有相同的函数名称,但形参不同的函数。(可以是参数类型不同,例如一个是double,一个是int;也可以是参数个数不同,例如一个含有2个参数,一个含有3个参数)
这里直接上图,看的清楚一些:
在这里插入图片描述
可以看到,方法名都是相同的,但参数个数与参数类型不同。在main方法中调用时,编译器会根据实参进行逐个匹配,选择正确的方法;如果匹配失败,则编译器会报错。

4.可变参数

一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何方法的参数必须在它之前声明。
简单尝试:

public class Main {
    public static void main(String[] args) {
        Demo3 demo3 = new Demo3();
        demo3.test(1,2,3,4,5);	//此处可输出任意个int型数字
    }

    public void test(int ... i){
        for (int j = 0; j < 5; j++) {
            System.out.println(i[j]);
        }
    }
}

求最大值:

public class Main {
    public static void main(String[] args) {
        //调用可变参数的方法
        printMax(34,3,3,2,56.5);    //随意输入,只要为double都可以
    }

    public static void printMax(double... numbers){
        if(numbers.length == 0){    //没有传参数
            System.out.println("No argument passed");
            return;
        }

        double result = numbers[0]; //定义返回值

        //求最大值
        for (int i = 1; i < numbers.length; i++) {
            if(numbers[i] > result)
                result = numbers[i];
        }
        System.out.println("The max value is:" + result);
    }
}

5.递归

递归重要组成部分:
①递归头:什么时候不调用自身方法,也就是递归结束条件。如果没有递归出口,将会陷入死循环。
②递归体:什么时候需要调用自己。
如果能理解栈,那递归就好理解了,递归实质就是一个进栈出栈的过程。
阶乘(学一次递归就来一遍阶乘):

public class Main {
    public static void main(String[] args) {
        System.out.println(f(5));
    }

    public static int f(int n){
        if(n == 1)
            return 1;
        else
            return  n * f(n - 1);
    }
}

6.例题

写一个计算器,要求实现加减乘除功能,并且能够循环接收新的数据,通过用户交互实现。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()){
            double a = scanner.nextDouble();    //接收第一个数字
            String op = scanner.next(); //接收符号
            double b = scanner.nextDouble();    //接收第二个数字
            double result;  //接收参数

            switch (op) {
                case "+" -> result = add(a, b);
                case "-" -> result = minus(a, b);
                case "*" -> result = multiple(a, b);
                case "/" -> result = divide(a, b);
                default -> result = -1; //接收到的op非+-*/中的一个
            }

            System.out.println(result);
        }

        scanner.close();
    }

    //加法
    public static double add(double a, double b){
        return a + b;
    }
    //减法
    public static double minus(double a, double b){
        return a - b;
    }
    //乘法
    public static double multiple(double a, double b){
        return a * b;
    }
    //除法
    public static double divide(double a, double b){
        return a / b;
    }
}

四、数组

1.数组的基本特点

①数组的长度是确定的,一旦被创建,它的大小就不可以改变。
②其元素必须是相同类型。
③数组中的元素可以是任何数据类型,包括基本类型和引用类型。
④数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组对象本身是在堆中的。

2.静态初始化与动态初始化

动态初始化包含了默认初始化,即没有重新赋值过的元素默认值为0。

public class Main {

    public static void main(String[] args) {
        //静态初始化
        int[] a = {0, 1, 2, 3, 4, 5};
        for (int j : a) {
            System.out.print(j + " ");
        }
        System.out.println();

        //动态初始化,包含默认初始化
        int[] b = new int[10];
        b[0] = 10;
        System.out.println("第一个元素是:" + b[0]);
        System.out.println("第二个元素是:" + b[1]);   //默认初始化为0
        System.out.println("第三个元素是:" + b[2]);   //默认初始化为0
    }
}

3.数组基本操作

public class Main {
    public static void main(String[] args) {
        int[] a = {0,1,2,3,4,5};

        //打印全部数组元素
        for (int j : a) {
            System.out.print(j + " ");
        }
        System.out.println("\n--------------------");

        //计算所有元素和
        int sum = 0;
        for (int j : a){
            sum = sum + j;
        }
        System.out.print("数组总和为:" + sum);
        System.out.println("\n--------------------");

        //查找最大元素
        int max = a[0];
        for (int i = 1; i < a.length; i++) {
            if(a[i] > max){
                max = a[i];
            }
        }
        System.out.println("最大值是:" + max);
    }
}

4.数组进阶操作

public class Main {
    public static void main(String[] args) {
        int[] arrays = {0,1,2,3,4,5};

        //打印数组元素
        printArrays(arrays);

        //打印反转后的数组
        int[] reverse = reverse(arrays);
        printArrays(reverse);
    }

    //打印数组元素
    public static void printArrays(int[] arrays){
        for (int i = 0; i < arrays.length; i++) {
            System.out.print("原数组为:" + arrays[i] + " ");
        }
        System.out.println();
    }

    //反转数组
    public static int[] reverse(int[] arrays){
        int[] result = new int[arrays.length];
        for (int i = arrays.length - 1, index = 0; i >= 0; i--, index++) {
            result[index] = arrays[i];
        }
        return result;
    }
}

5.多维数组

打印多维数组,重点在第二个for循环的条件,j < array[i].length 是我从未设想过的套路,学到了。

public class Demo5 {
    public static void main(String[] args) {
        int[][] array = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                System.out.print(array[i][j] + " ");
            }
        }
    }
}

6.常用的Arrays类

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] array = {1,2,3,9,6,80,50,42,555,805,15,666};
        System.out.println(array);  //[I@16b98e56,是个对象

        //打印数组元素,Arrays.toString方法
        System.out.println(Arrays.toString(array));

        //排序,升序
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));

        //数组填充,下标为2的元素到下标为4的元素被0填充,其余保持不变
        Arrays.fill(array,2,4,-1);
        System.out.println(Arrays.toString(array));
    }
}

7.冒泡排序与简单优化

时间复杂度:O(n^2)

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] array = {1,5,6,9,2,10,7};
        sort(array);
        System.out.println(Arrays.toString(array));
    }

    /*
    冒泡排序
    比较数组中两个相邻元素,如果第一个数比第二个数大,则交换两者的位置
    每一次比较都会产生一个最大或最小的数字
    下一轮可以少一次排序
    依次循环,直至结束
     */

    public static void sort(int[] array){
        int temp;
        //外层循环,判断循环要走多少次,length-1防止溢出
        for (int i = 0; i < array.length-1; i++) {
            boolean flag = false;   //通过flag标志位减少没有意义的比较

            //内层循环,如果前一个数比后一个数大,则交换位置
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j+1] < array[j]){
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                    flag = true;
                }
            }
            if(!flag)   //没有进行比较交换
                break;
        }
    }
}

8.稀疏数组

概念:当一个数组中大部分元素为0,或者为同一值的数组时,可以使用稀疏数组来保存该数组。
处理方式:
①记录数组一共有几行几列,有多少个不同值。
②把具有不同值的元素、所在行列、值记录在一个小规模数组中,从而缩小程序的规模,节省空间。

public class Main {
    public static void main(String[] args) {
        //创建一个二维数组 11*11    0:没有棋子    1:黑棋    2:白棋
        int[][] array1 = new int[11][11];
        array1[1][2] = 1;
        array1[2][3] = 2;
        //输出原始数组
        System.out.println("打印原始数组:");
        for (int[] ints : array1) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
        System.out.println("====================");
        
        //1.转换为稀疏矩阵保存
        //获取有效值的个数
        int sum = 0;
        for (int i = 0; i < 11; i++) {
            for (int j = 0; j < 11; j++) {
                if (array1[i][j] != 0)
                    sum++;
            }
        }
        System.out.println("有效值的个数:" + sum);
        
        //2.创建一个稀疏数组的数组
        int[][] array2 = new int[sum+1][3]; //int[a][b],a为有效数字+第0行,b固定为3(行、列、值)
        array2[0][0] = 11;  //行数
        array2[0][1] = 11;  //列数
        array2[0][2] = sum; //有效数字个数
        
        //3.遍历二维数组,将非零的值存入稀疏数组
        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];    //存入值
                }
            }
        }

        //4.输出稀疏数组
        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]);
        }
        System.out.println("====================");

        //5.还原稀疏数组
        System.out.println("还原:");
        //读取稀疏数组
        int[][] array3 = new int[array2[0][0]][array2[0][1]];
        //还原其中的元素
        for (int i = 1; i < array2.length; i++) {
            array3[array2[i][0]][array2[i][1]] = array2[i][2];
        }
        for (int[] ints : array3) {
            for (int anInt : ints) {
                System.out.print(anInt + "\t");
            }
            System.out.println();
        }
    }
}

五、面向对象

面向对象编程的本质:以类的方式组织代码,以对象的形式组织(封装)数据。
核心思想:抽象
三大特性:封装。继承。多态

静态方法:类名 . 方法名
非静态方法(实例化对象):
①类名 对象名 = 对象值
②对象名 . 方法名

1.简单demo练习

ps:要写在一个package下

Application类:

public class Application {
    public static void main(String[] args) {

        //类:抽象的,需要实例化
        //类实例化后会返回一个自己的对象
        //student对象就是Student类的具体实例
        Student student = new Student();    //实例化对象
        student.name = "张三";
        student.age = 18;
        System.out.println(student.name + "今年" + student.age + "岁了!");
    }
}

Student类:

//学生类,类中只有属性和方法
public class Student {

    //属性:字段
    String name;
    int age;

    //方法
    public void study(){
        System.out.println(this.name + "在学习");  //this代表当前类
    }
}

2.构造器

打开.class文件:Ctrl + shift + alt + S,Add Content Root,选择out文件。
alt + insert会生成一个构造器。

特点:
①必须和类的名字相同。
②必须没有返回类型,也不能写void。

作用:
①使用new关键字,本质是在调用构造器。
②用来初始化值。

注意点:
定义有参构造之后,如果想继续使用无参构造,显示的定义一个无参的构造。

Application_Person类:

public class Application_Person {
    public static void main(String[] args) {

        //new实例化了一个对象
        Person person = new Person();
        System.out.println(person.name);
    }
}

Person类:

public class Person {
    //显示的定义构造器

    String name;

    //实例化初始值,无参构造器
    public Person(){
        this.name = "张三";
    }

    //有参构造器
    public Person(String name){
        this.name = name;
    }
}

3.封装

大多数是对于属性,对方法应用的较少。
属性为private,不允许外部直接对属性进行修改。
但是提供一些 public 的 get 和 set 的外部方法,进而修改属性。get :获得这个数据;set:给这个数据设置值。

alt + insert 自动生成 get、set 方法

作用:
①提高程序安全性,保护数据
②影藏代码的实现细节
③统一接口
④增加系统的可维护性

Application类:

public class Application {
    public static void main(String[] args) {
        Student student1 = new Student();

        student1.setName("张三");
        System.out.println(student1.getName());

        student1.setAge(888);
        System.out.println(student1.getAge());
    }
}

Student类:

public class Student {

    //属性私有
    private String name;
    private int id;
    private char sex;
    private int age;

    //提供get、set方法可以操作属性
    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name = name;
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }

    public char getSex() {
        return sex;
    }
    public void setSex(char sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        if(age > 120 || age < 0){
            this.age = 999999;
        }
        else
            this.age = age;
    }
}

例如 age 这里,可以在 setAge 方法中判断修改的数据是否合法,保证了系统的安全性与数据的正确可靠。

4.继承

关键词:extends
①子类继承父类,就会拥有父类的全部方法(仅public修饰,private无法继承,除非使用 get 和 set)。
②在Java中,所有的类都默认继承Object类,即Object类是所有类的父类。
③在Java中,类只有单继承,没有多继承。即一个子类只能有一个父类,一个父类可以有多个子类。

Application类:

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        Teacher teacher = new Teacher();

        //public方法直接调用
        //student与teacher均已继承Person中的全部属性与方法
        student.say();
        teacher.say();

        //private属性用 get 获取
        System.out.println(student.getMoney());
    }
}

Person类(父类):

//Person,父类
public class Person {

    private int money = 10_000_000;

    public void say(){
        System.out.println("说了一句话");
    }

    public int getMoney() {
        return money;
    }
    public void setMoney(int money) {
        this.money = money;
    }
}

Student类(继承自Person类):

//Student is Person,子类
public class Student extends Person{

}

Teacher类(继承自Person类):

//Teacher is Person,子类
public class Teacher extends Person{

}

关键词:super

①子类调用父类的属性或方法,必须在构造方法的第一个。
② super 必须只能出现在子类的方法或构造方法中。
③ super 和 this 不能同时调用构造方法。
Application类:

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.test("我是传入的张三");

    }
}

Person类(父类):

//Person,父类
public class Person {
    protected String name = "我是父类张三";
}

Student类(继承自Person类的子类):

//Student is Person,子类
public class Student extends Person{
    private String name = "我是子类张三";

    public void test(String name){
        System.out.println(name);   //传入的参数
        System.out.println(this.name);  //该类中定义的属性
        System.out.println(super.name); //父类中的属性
    }
}

输出结果:

我是传入的张三
我是子类张三
我是父类张三

重写

需要有继承关系,即子类重写父类的方法,且都是非静态方法的重写。

为什么需要重写?
父类的功能,子类不一定需要,或者不一定满足。

关键点:
①方法名必须相同。
②参数列表必须相同。
③方法体不同。
④修饰符范围可以扩大,但不能缩小:例如父类为 default ,子类重写为 public 等。范围private < default < protected < public。在重写中, private 不能使用!
⑤抛出的异常:范围可以缩小,但不能扩大。

注:静态方法和非静态方法区别很大!静态方法是类的方法(类的成员),非静态方法是对象的方法(对象的成员)。

Application类:

public class Application {
    public static void main(String[] args) {

        A a = new A();
        a.test();
        
        B b= new A();
        b.test();
    }
}

B类(父类):

public class B {

    public void test(){
        System.out.println("B=>test()");
    }
}

A类(子类):

public class A extends B{

    public void test(){
        System.out.println("A=>test()");
    }
}

输出结果:

A=>test()
A=>test()

5.多态

定义:即统一方法可以根据发送对象的不同而采取多种不同的行为方式。
可以实现动态编译,使可扩展性变得更强。
多态注意事项:
①多态是方法的多态,属性没有多态。
②存在于父类与子类中,只有父子之间才能转换,否则会出现类型转换异常。ClassCastException!
③存在条件:继承关系、方法重写、父类的引用指向子类对象。Father f1 = new Student ( ) ;

无法重写的三种情况(无法被重写,就更不可能实现多态):
① static 方法,属于类,不属于实例。
② final 表示修饰的是常量,不可被更改。
③ private 方法,无法被重写

Application类:

public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //可以指向的引用类型不确定:父类的引用类型指向子类
        Student s1 = new Student(); //能调用的方法是自己的,或继承自父类的
        Person s2 = new Student();  //父类能指向子类,但不能调用子类独有的方法
        Object s3 = new Student();

        //对象能执行的方法,主要看对象左边的类型
        s1.run();
        s2.run();   //子类重写了父类的方法

        s1.eat();
        //s2.eat();   //s2的类型是Person,Person中没有eat方法
    }
}

Person类:

public class Person {

    public void run(){
        System.out.println("FatherRun");
    }
}

Student类:

public class Student extends Person{

    @Override
    public void run() {
        System.out.println("SonRun");
    }

    public void eat(){
        System.out.println("SonEat");
    }
}

关键词:instanceof
用于判断两个类之间是否有父子关系。
这里就贴一个Application类,其他类之间的关系如注释:

public class Application {
    public static void main(String[] args) {

        //Object > Person > Student
        //Object > Person > Teacher
        //Object > String
        Object object = new Student();

        System.out.println(object instanceof Student);  //true
        System.out.println(object instanceof Person);   //true
        System.out.println(object instanceof Teacher);  //false
        System.out.println(object instanceof Object);   //true
        System.out.println(object instanceof String);   //false
    }
}

强制类型转换:
①父类引用指向子类的对象
②把子类转换为父类(向上转型),不用强制类型转换,直接进行。
③把父类转换为子类(向下转型),需要强制类型转换。
④方便方法的调用,减少重复的代码。

public class Application {
    public static void main(String[] args) {

        Person obj = new Student(); //此时的obj不能用Student类中的go()方法,Person > Student
        ((Student)obj).go();   //强制将Person类型的obj转化为Student类,即可调用go()方法

        //子类转换为父类,可能丢失自己本来的一些方法
        Student student = new Student();
        student.go();   //正常调用go()方法
        Person person = student;    //低转高,可自动转化
    }
}

6. static

静态属性:

public class Student {
    
    private static int age; //静态变量
    private double score;   //非静态变量

    public static void main(String[] args) {
        Student s1 = new Student();

        System.out.println(Student.age);	//静态属性可直接通过 类.属性 进行调用
        System.out.println(s1.score);
        System.out.println(s1.age);
    }
}

静态方法:

静态方法是与类一起加载的,类一旦存在,静态方法即存在。
(大白话理解:类是最先被加载的,静态方法同类一起被加载,所以静态方法出现的特别早;而非静态方法出现的相对较晚。)

所以,非静态方法可以访问静态方法,静态方法可以访问静态方法;静态方法不可以访问非静态方法!
(大白话理解:①非静态方法被加载时,静态方法早已和类一起被加载了,当然可以被调用;②静态方法都是与类一同被加载的,其之间当然可以互相调用;③静态方法加载时,非静态方法还没被加载呢,所以当然不能调用!)

static 可以扩大访问范围。

public class Student {
    
    public void run(){
        go();
    }

    public static void go(){

    }

    //main方法
    public static void main(String[] args) {

        //非静态方法:实例化对象后才能调用
        Student student = new Student();
        student.run();

        //静态方法:两种方法均可,同一个类中推荐直接使用
        student.go();   //能用,但不推荐
        go();   //推荐使用
    }
}

静态代码块:

public class Main {

    //匿名代码块,静态代码块之后被加载
    {
        System.out.println("匿名代码块");
    }

    //静态代码块,最先被加载,只执行一次
    static {
        System.out.println("静态代码块");
    }

    //构造器,最后被加载
    public Person() {
        System.out.println("构造方法");
    }

    //main方法
    public static void main(String[] args) {
        Person p1 = new Person();
        System.out.println();
        Person p2 = new Person();

    }
}

输出结果:

静态代码块
匿名代码块
构造方法

匿名代码块
构造方法

可以看到,执行顺序:静态代码块 > 匿名代码块 > 构造方法,但是静态代码块只执行一次。

静态导入包:

import static java.lang.Math.random;
import static java.lang.Math.PI;

public class Main {
    public static void main(String[] args) {
        System.out.println(random());
        System.out.println(PI);
    }
}

7.抽象类

关键词:abstract

①不能 new 这个抽象类,只能靠子类去实现它;就是个约束!
②抽象类中可以写普通方法。
③抽象方法必须在抽象类中。

Action类(抽象类,是父类):

//抽象类
public abstract class Action {

    //约束,在子类中实现
    //抽象方法,只有方法名字,没有方法的实现
    public abstract void doSomething();
}

A类(继承自Action类,是子类):

//继承了抽象类的子类,必须实现原抽象类中的全部方法(除非子类也是抽象类)
//也就是子类对父类的重写
public class A extends Action{

    @Override
    public void doSomething() {

    }
}

8.接口

关键词:
interface(定义接口)
implements(实现接口)

普通类:只有具体实现。
抽象类:具体实现和规范(抽象方法)都有,只是不能 new ,需要子类去操作。
接口:只有规范,自己无法写方法。实现约束和实现分离。

接口的本质是契约,是 OO 的精髓,是对对象的抽象。
接口不能被实例化,因为接口中没有构造方法。

interface 与 abstract:
①abstract:抽象类,通过 extends 单继承,然后进行实现(重写)。
②interface:接口类,通过 implements 多继承,然后进行实现(重写)。

UserService类(使用 interface 定义接口):

//interface 需要有实现类
public interface UserService {

    //属性默认为常量 public static final
    int age = 99;

    //接口中的所有定义的方法默认都是抽象的 public abstract
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}

TimeService类(使用 interface 定义接口):

public interface TimeService {
    void timer();
}

UserServiceImpl类(使用implements实现 UserService 与 TimeService 两个接口):

//使用implements实现接口
public class UserServiceImpl implements UserService, TimeService{
    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void query(String name) {

    }

    @Override
    public void timer() {

    }
}

9.内部类

成员内部类:

内部类可以获取外部类的私有属性。

Application类,通过外部类来定义内部类:

public class Application {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.in();
    }
}

Outer类与其内部类Inner:

public class Outer {

    private int id;
    public void out(){
        System.out.println("这是外部类的方法");
    }

    //内部类
    public class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }

        //获得外部类的私有属性
        public void getID(){
            System.out.println(id);
        }
    }
}

局部内部类:

public class Outer {

    public void method() {
        //局部内部类
        class Inner {
            public void in() {

            }
        }
    }
}

匿名内部类:

是局部内部类的一种形式,也要写在方法里
前提:存在一个类或者接口,这里的类可以使具体类也可以是抽象类。
本质:是一个继承了该类或者实现了该接口的子类匿名对象

格式(就是个对象):

new Inner(){	//Inner是接口名
            @Override
            public void show() {	//重写接口中的方法
                System.out.println("匿名内部类");
            }
        };	//注意分号

Application 类:

public class Application {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();
    }
}

Outer 类:

public class Outer {

    public void method(){
        new Inner(){
            @Override
            public void show() {
                System.out.println("匿名内部类");
            }
        }.show();   //本质:对象调用了show方法
    }
}

Inner 接口:

public interface Inner {
    void show();    //抽象方法
}

六、异常机制

异常Exception:检查性异常、运行时异常
错误Error

快捷键:ctrl + alt + t

try:尝试,必须要有。
catch:捕获,必须要有。catch(想要捕获的异常类型)。
finally:无论有无异常都会执行的部分,可有可无。关闭 IO 流、资源等操作可以放在 finally 中。
throw:抛出
throws:抛出

简单异常捕获:

public class Main {
    public static void main(String[] args) {

        int a = 1;
        int b = 0;

        try {   //监控区域  必须要
            System.out.println(a/b);
        }catch (ArithmeticException e){ //捕获异常  必须要
            System.out.println("程序出现异常,变量b不能为0");
        }finally {  //处理善后工作,无论有无异常,都会执行    可以不要
            System.out.println("finally");
        }
    }
}

输出结果:

程序出现异常,变量b不能为0
finally

若不使用异常捕获,则会出现如下报错:

多个异常捕获:

假设有多个异常要捕获,可以使用多个 catch ,必须从低到高层层递进。如果一开始就使用最高层级的 Throwable 进行捕获(一定能抓到异常),则后续的捕获不会被执行。

public class Main {
    public static void main(String[] args) {

        int a = 1;
        int b = 0;

        try {   //监控区域
            System.out.println(a/b);
        } catch (Error e){
            System.out.println("Error");
        }catch (Exception e){
            System.out.println("Exception");
        }catch (Throwable t){
            System.out.println("Throwable");
        } finally {  //处理善后工作,无论有无异常,都会执行    可以不要
            System.out.println("finally");
        }
    }
}

后记:
差不多JavaSE就学到这里啦,后续可能会补充知识点啥的…吧?
路还很长,继续努力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值