Loading...
墨滴

国家一级抬杠运动员、

2021/06/15  阅读:73  主题:默认主题

Java基础

Java基础知识

一、基础部分

1.1 转义符:

\t 一个制表位,实现对齐功能

public class Test {
    public static void main(String[] args) {
        System.out.println("北京\t天津\t上海");
    }
}
// 这个就会返回一个制表位

\n 换行符

public class Test {
    public static void main(String[] args) {
        System.out.println("北京\n天津\n上海");
    }
}
// 这个是换行

转义一个符号:写一个斜杠就可以

public class Test {
    public static void main(String[] args) {
        System.out.println("c:\\windos\\Systme32\\cmd.exe");
        System.out.println("老韩说:\"要好好学习java,有前途;\"");
    }
}
// 这个是反斜杠\转移

1.2 +号的使用

两边都是数值的话,是数值相加

public class Test {
    public static void main(String[] args) {
        int a = 12;
        int b = 13;
        int c = 26;
        System.out.println(a + b + c);
    }
}

如果是跟字符串相加的话是拼接字符串

public class Test {
    public static void main(String[] args) {
        int a = 12;
        int b = 13;
        int c = 26;
        String e = "我是字符串";
        System.out.println(e + a + b + c);
    }
}

1.3 数据类型

image-20210604095416028
image-20210604095416028
image-20210604095439855
image-20210604095439855

整数类型的范围

image-20210604095624219
image-20210604095624219

浮点数的注意事项

// 默认是double类型,所以说在定义float类型必须要加上大写F
public class Test {
    public static void main(String[] args) {
        float a = 122.02F;
        System.out.println(a);
    }
}

基本数据类型的默认值

int是0

double是0.0

char是0或者是字码的

short是0

boolean是flase

long是0

float是0.0

public class Test {
    public static void main(String[] args) {
        Person i = new Person();
        System.out.println(i.a);
        System.out.println(i.b);
        System.out.println(i.c);
        System.out.println(i.e);
        System.out.println(i.d);
        System.out.println(i.f);
        System.out.println(i.l);
    }
}
class Person{
    int a;
    double b;
    char c;
    short e;
    boolean d;
    long f;
    float l;
}

1.4 基础数据类型转换

image-20210604110820798
image-20210604110820798
public class Test {
    public static void main(String[] args) {
        char a = 'a'//定义一个char类型
        int b = a; // 自动类型隐士转换,char类型转成int类型
        double c = a; // 自动类型隐士转换,char类型转成double类型
    }
}

1.5 强制类型转换

就是在类型前面加上一个(类型)

image-20210604112318911
image-20210604112318911
public class Test {    public static void main(String[] args) {        int a = 12;        char b = 3;        double c = 12.93;        int e = (int)c;        System.out.println(e);    }}

如果强制类型转换,转成byte类型超出了128,-127会造成内存溢出

public class Test {    public static void main(String[] args) {        int n2 = 2000;        byte b1 = (byte)n2;        System.out.println("b1=" + b1);    }}

强转的符号只针对最近的才有效


1.6 基本数据类型转字符串

用+号连接就行

public class Test {    public static void main(String[] args) {        int n1 = 100;        float f1 = 1.1F;        double d1 = 2.34;        System.out.println(n1 + "");        System.out.println(f1 + "");        System.out.println(d1 + "");    }}

1.7 字符串转基本数据类型

可以用包装类

public class Test {    public static void main(String[] args) {        String s5 = "123";        int i = Integer.parseInt(s5);        double v = Double.parseDouble(s5);        float v1 = Float.parseFloat(s5);        long l = Long.parseLong(s5);        byte b = Byte.parseByte(s5);        boolean aTrue = Boolean.parseBoolean("true");        short i1 = Short.parseShort(s5);        System.out.println(i);        System.out.println(v);        System.out.println(v1);        System.out.println(l);        System.out.println(b);        System.out.println(aTrue);        System.out.println(i1);    }}

将字符串转成char类型

可以用字符串的一个方法charAt

public class Test {    public static void main(String[] args) {        String s5 = "123";        for (int i = 0; i < s5.length(); i++) {            System.out.println(s5.charAt(i));        }    }}

1.8 逻辑运算符

短路与(&&)和逻辑与(&)的区别

(&&): 两边的条件都是true才可以执行

// 这个是正确的public class Test_tw {    public static void main(String[] args) {        int a = 50;        if(a > 40 && 60 < a){            System.out.println("管吉航");        }    }}

下面这个是错误的,其中一个不满足条件

// 这个是不运行的public class Test_tw {    public static void main(String[] args) {        int a = 50;        if(a > 40 && 60 < a){            System.out.println("管吉航");        }    }}

(&): 两边的条件都是true才可以执行

public class Test_tw {    public static void main(String[] args) {        int a = 50;        if(a > 20 & a > 40){            System.out.println("管吉航2");        }    }}

下面这个是错误的,其中一个不满足条件

// 这个是不运行的public class Test_tw {    public static void main(String[] args) {        int a = 50;        if(a > 20 & a < 40){            System.out.println("管吉航2");        }    }}

&&短路与和&逻辑与的区别

&&短路与:当左边条件为flase的时候后面的不去执行

// 这个是错误的public class Test_tw {    public static void main(String[] args) {        int a = 10;        int b = 12;        if(a > b && ++b < a) {            System.out.println("管吉航3");        }        System.out.println(b);    }}

&逻辑与:左边的条件为false的时候,后面的条件仍然会执行

// 这个是错误的public class Test_tw {    public static void main(String[] args) {        int a = 10;        int b = 12;        if(a > b & ++b < a) {            System.out.println("管吉航3");        }        System.out.println(b);    }}

短路或(||)和逻辑或(|)的区别

(||): 两边的条件只要有一个成立,才可以执行

// 这个是正确的public class Test_tw {    public static void main(String[] args) {        int a = 50;        if(a > 40 || 60 < a){            System.out.println("管吉航");        }    }}

下面这个是错误的,没有一个满足条件

// 这个是错误的public class Test_tw {    public static void main(String[] args) {        int a = 50;        if(a < 40 || 60 < a){            System.out.println("管吉航");        }    }}

(|): 满足一个条件为true就可以执行

// 这个是正确的public class Test_tw {    public static void main(String[] args) {        int a = 50;        if(a > 40 | 60 < a){            System.out.println("管吉航");        }    }}

下面这个是错误的,没有一个满足条件

// 这个是错误的public class Test_tw {    public static void main(String[] args) {        int a = 50;        if(a < 40 | 60 < a){            System.out.println("管吉航");        }    }}

短路或(||)和逻辑或(|)的区别

短路或(||) 如果第一个条件为true,则第二个条件不会判断,最终结果为true,效率高

// 这个是正确的public class Test_tw {    public static void main(String[] args) {        int a = 4;        int b = 9;        if(a > 1 || ++b > 4){            System.out.println("ok300");        }        System.out.println(b);    }}

逻辑或(|)  不管第一个条件是否为true第二个条件都是判断效率低

// 这个是正确的public class Test_tw {    public static void main(String[] args) {        int a = 4;        int b = 9;        if(a > 1 | ++b > 4){            System.out.println("ok300");        }        System.out.println(b);    }}

逻辑异或

逻辑异或 ^ 左边的条件和右边的条件不同时,则结果为true,否则为flase

public class Test_tw {    public static void main(String[] args) {     // 这个返回的是false,两边都是返回的true        boolean b = (10 > 1) ^ (3 < 5);        System.out.println(b);    }}

1.9 三元运算符

语法:条件表达式?表达式1:表达式2;

如果表达式为true,则返回表达式1,为假返回表达式2;

public class Test_tw {    public static void main(String[] args) {     int a = 10;        int b = 99;        int result = a > b? a++ : b--;        System.out.println(result);        System.out.println(b);    }}

1.9.1 标识符的命名规则

image-20210604152907430
image-20210604152907430

1.9.2 键盘输入语句

需要一个扫描器(对象),就是Scanner

步骤:1)导入该类的所在包,java.util.*

​ 2) 创建该类对象(声明变量)

​ 3) 调用里面的功能

import java.util.Scanner;public class Test_tw {    public static void main(String[] args) {        // 1. 引入/导入Scanner类所在的包        // 2. 创建Scanner对象,new 创建一个对象        Scanner sc = new Scanner(System.in);        // 3. 接收用的输入        System.out.println("请输入名字");        String next = sc.next(); // 这个是输入字符串的        int a = sc.nextInt(); // 这个是输入数字的        double b = sc.nextDouble(); // 浮点型输入    }}

二、第二部分

2.1 switch

格式:case 常量:

条件语句

break;

.....

default: (没有满足的条件最终执行default的代码块)

public class Test_two {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        System.out.println("请输入一个字符(a-g)");        char c = sc.next().charAt(0);        switch(c) {            case 'a':                System.out.println("今天是星期一,猴子穿新衣服");                break;            case 'b':                System.out.println("今天是星期二,猴子当小二");                break;            case 'c':                System.out.println("今天是星期三,猴子爬雪山...");                break;            default:                System.out.println("你输入的字符不正确");        }    }}

switch注意事项:

  1. 表达式的数据类型,应和case后的常量保持一致,或者是自动转成相互比较的类型

  2. switch(表达式)中表达式的返回值必须是: (byte、short、int、char、enum、String) 别的数据类型不可以

    • 表达式中可以写运算
  3. case子句中的值必须是常量,而不能是变量

    • 变量:值是固定的

    • 变量: 值可以更改

      1. break是必须带的,如果不带的话程序会一直执行到switch结尾。

2.2 数组

静态数组 :数组的元素和长度都规定好了

格式:类型[ ] array = {元素个数,元素个数......}

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

动态初始化 : 规定好长度,不规定好元素

格式:数据类型 数组名[ ] = new 数据类型[大小];

    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int[] array = new int[5];        for (int i = 0; i < array.length; i++) {//            array[i] = 1;            int i1 = sc.nextInt();            array[i] = i1;        }        for (int i = 0; i < array.length; i++) {            System.out.println(array[i]);        }    }}

注意事项: 不能把一个高精度的给一个低精度的

数组的初始值,和基本数据类型的初始值一样

数组下标必须在指定范围内使用,否则报:下标越界异常

数组属于引用数据类型,数组型数据是对象(object);


2.3 数组的赋值机制

基本数据类型赋值,赋值方式为值拷贝/值拷贝

public class Test {    public static void main(String[] args) {        int n1 = 10;        int n2 = n1;        n2 = 80;        System.out.println("n1=" + n1);   // 10        System.out.println("n2=" + n2);   // 80    }}

数组在默认情况下是引用转递,赋的值是地址值,赋值的方式为引用赋值

public class Test_two {    public static void main(String[] args) {        int[] arr = {1,2,3,4};        int [] arr2 = arr;        arr2[0] = 10;        System.out.println("------------");        for(int i = 0; i < arr2.length; i++){            System.out.println(arr2[i]);        }        System.out.println("------------");        for(int j = 0; j < arr.length; j++){            System.out.println(arr[j]);        }    }}

2.4 二维数组

静态二维数组

格式:数据类型[ ] [ ] = {{},{},{}};

public class Test_two {    public static void main(String[] args) {        int[][] arr = {{000000},                       {001000},                       {020300},                       {000000}};        // arr[i] 表示 二维数组的第i+1个元素,比如arr[0]:二维数组的第一个元素        // arr[i].lenth 得到 对应的 每一个一维数组        for(int i = 0; i < arr.length; i++) {            for(int j = 0; j < arr[i].length; j++){                System.out.print(arr[i][j] + " ");            }            System.out.println();        }    }}

动态二维数组

格式:数据类型[ ] [ ] = new 类型[大小] [大小]

第一个大小值得是有几个一维数组,第二个大小指的是每个一维数组有多少个元素

public class Test_two {    public static void main(String[] args) {        int arr[][] = new int[2][3];        arr[1][1] = 8;        for(int i= 0; i < arr.length; i++){            for(int j = 0; j < arr[i].length; j++){                System.out.println(arr[i][j]  + " ");            }            System.out.println();        }    }}

也可以用给一维数组规定长度

去动态创建二维数组中一维数组的个数

public class Test_three {    public static void main(String[] args) {        int[][] arr = new int[3][];        // 遍历每一个一维数组        for (int i = 0; i < arr.length; i++) {            // 给每一个一维数组开辟空间new            // 如果没有给一维数组 new,那么 arr[i]就是null            arr[i] = new int[i + 1];            // 遍历一维数组,并给一维数组的每个元素赋值            for (int j = 0; j < arr[i].length; j++){                arr[i][j] = i + 1;            }        }        System.out.println("=======arr元素=======");        for (int i = 0; i < arr.length; i++) {            for(int j = 0; j < arr[i].length; j++){                System.out.print(arr[i][j] + " ");            }            System.out.println();        }    }}

杨辉三角案例

public class Test_four {    public static void main(String[] args) {        int[][] arr = new int[10][];        for (int i = 0; i < arr.length; i++) {            arr[i] = new int[i + 1];            for (int j = 0; j < arr[i].length; j++) {               if(j == 0 || j == arr[i].length - 1){                   // 第一个和最后一个永远是1                   arr[i][j] = 1;//                   System.out.print(arr);               } else{                   // 第一个和最后一个永远是1                   // 杨辉三角是前一个数+第二个数                   // arr[2][1] = arr[2 - 1][1] + arr[2 - 1][1 - 1] = 2                   arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];               }            }        }        for (int i = 0; i < arr.length; i++) {            for (int j = 0; j < arr[i].length; j++) {                System.out.print(arr[i][j] + " ");            }            System.out.println();        }    }}

已知有个升序的数组,要求插入一个元素,该数组顺序依然是升序,比如:[10, 12, 45, 9],添加23后,数组为[10, 12, 23, 45, 90]; 用到了扩容和定位

public class Test {    public static void main(String[] args) {        int[] arr = {10124590};        int insertNum = 23;        // index是判断23的位置        int index = -1;        for (int i = 0; i < arr.length; i++) {            // 对比arr数组的哪一个元素必23大            if(insertNum <= arr[i]){                index = i;                break;            }        }        // 这个是判断找到23的位置了没有        if(index == -1){            index = arr.length;        }        System.out.println("index=" + index);        System.out.println("arr.length = " + arr.length);        // 创建一个新的数组        int[] arrNew = new int[arr.length + 1];//        int[] arr = {10, 12, ,23 ,45, 90};  1  1  2 2  2 3 3 4 4 5        for (int i = 0, j = 0; i < arrNew.length; i++){            // 2 = 23;            if(i != index){ // 2                arrNew[i] = arr[j];                j++;            } else{                arrNew[i] = insertNum;            }        }        for (int i = 0; i < arrNew.length; i++) {            System.out.println(arrNew[i]);        }    }}

三、第三部分

3.1 面向对象

《Java编程思想》中提到“万物皆为对象”的概念。它将对象视为一种奇特的变量,它除了可以存储数据之外还可以对它自身进行操作。它能够直接反映现实生活中的事物,例如人、车、小鸟等,将其表示为程序中的对象。每个对象都具有各自的状态特征(也可以称为属性)及行为特征(方法),java就是通过对象之间行为的交互来解决问题的。

面向对象就是把构成问题的事物分解成一个个对象,建立对象不是为了实现一个步骤,而是为了描述某个事物在解决问题中的行为。

类是面向对象中的一个很重要的概念,因为类是很多个具有相同属性和行为特征的对象所抽象出来的,对象是类的一个实例。

类具有三个特性:封装、继承和多态。

  • 三大特征
    1. 封装:核心思想就是“隐藏细节”、“数据安全”,将对象不需要让外界访问的成员变量和方法私有化,只提供符合开发者意愿的公有方法来访问这些数据和逻辑,保证了数据的安全和程序的稳定。所有的内容对外部不可见。
    2. 继承:子类可以继承父类的属性和方法,并对其进行拓展。将其他的功能继承下来继续发展 。
    3. 多态:同一种类型的对象执行同一个方法时可以表现出不同的行为特征。通过继承的上下转型、接口的回调以及方法的重写和重载可以实现多态。方法的重载本身就是一个多态性的体现。
  • 三大思想
    1. 面向对象思想从概念上讲分为以下三种:OOA、OOD、OOP
    2. OOA:面向对象分析(Object Oriented Analysis)
    3. OOD:面向对象设计(Object Oriented Design)
    4. OOP:面向对象程序(Object Oriented Programming )
public class Test_two {    public static void main(String[] args) {        Person p1 = new Person();        String color = p1.color = "red";        int age = p1.age =  18;        String name = p1.name = "小白";        System.out.println("这只猫的名字叫: " + name + " 年龄是:" + age + "颜色是: " + color);    }}class Person{    String name; // 成员变量,属性,field(字段)    int age;    String color;    String[] master; // 属性可以是基本数据类型也可以是引用数据类型}

3.2 创建对象

public class Test_four {    public static void main(String[] args) {        // 创建对象        // 先声明再创建        Person_two p1;        p1 = new Person_two();        // 直接创建        Person_two p2 = new Person_two();    }}class Person_two{    String name;    int age;    String sex;}

3.3 类和对象的内存分配机制

java内存的结构分析

  1. 栈:一般存放基本数据类型(局部变量)
  2. 堆:存放对象(Cat car,数组等)
  3. 方法区:常量池(常量, 比如字符串),类加载信息

3.4 成员方法的好处

  1. 提高代码的复用性
  2. 可以将实现的细节封装起来,然后供其他用户来调用即可。

3.5 方法的重载(OverLoad)

  • 基本介绍

    java中允许同一个类中,多个同名方法的存在,但要求 形参列表不一致!

    比如:System.out.println(""); out是PrintStream类型

  • 重载的好处

    减轻了起名的麻烦

    减轻了记名的麻烦

注意事项:方法名:必须相同;形参列表:必须不同(参数类型或个数或顺序,至少有一样不同,参数名无要求);返回类型无要求


3.6 可变参数

  • 基本概念

    java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。就可以通过可变参数实现

  • 基本语法

    访问权限修饰符 返回类型 方法名(数据类型... 形参名){

    ​ 代码块;

    }

public class JavaDemo {    public static void main(String[] args) {        HspMethod p1 = new HspMethod();        int sum = p1.sum(12345);        System.out.println(sum);    }}class HspMethod {    public int sum(int... nums) {        System.out.println("接收的参数个数=" + nums.length);        int res = 0;        for (int i = 0; i < nums.length; i++) {            res += nums[i];        }        return res;    }}

注意事项:

  1. 可变参数的实参可以为0个或任意多个。
  2. 可变参数的实参可以为数组
  3. 可变参数的本质就是数组
  4. 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
  5. 一个形参列表中只能出现一个可变参数

3.7 作用域

全局变量(属性)可以不赋值,直接使用,因为又默认值,局部变量必须赋值后才可以使用,因为没有默认值

修饰符不同,全局变量/属性可以加修饰符,局部变量不可以加修饰符

public class JavaDemo {    public static void main(String[] args) {        HspMethod p1 = new HspMethod();        p1.sum();    }}class HspMethod {    int a;   // 全局变量是可以使用的    public void sum(){        int b;   // 这个局部变量就不可以使用        int a;        System.out.println(b);    }}

3.8 构造器

构造方法又称构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。它有几个特点:

  1. 方法名和类名相同
  2. 没有返回值
  3. 在创建对象时,系统会自动的调用该类的构造器完成对象的初始化
  4. 构造器是完成对象的初始化,并不是创建对象
  5. 在创建对象时,系统自动的调用该类的构造方法
  6. 如果程序员没有定义构造器,系统会自动给类生成一个默认的无参构造器
  7. 一旦定义了自己的构造器,默认的构造器就覆盖,就不能再使用默认的无参构造器,除非显示的定义一下
public class javaDemo_two {    public static void main(String[] args) {        Person_Three king = new Person_Three("king"40);        Person_Three smith = new Person_Three("smith");    }}class Person_Three {    String name;    int age;    public Person_Three(String pName, int pAge){        System.out.println("第一个构造器被调用");        name = pName;        age = pAge;    }    public Person_Three(String pName) {        System.out.println("第二个构造器被调用");        name = pName;    }}

3.9 this的关键字

  1. this 关键字可以用来访问本类的属性、方法、构造器
  2. this用于区分当前类的属性和局部变量
  3. 访问成员方法的语法:this.方法名(参数列表);
  4. 访问构造器语法:this(参数列表);   注意只能在构造器中使用(即只能构造器中访问另外一个构造器,必须放在第一条语句)
  5. this不能在类定义的外部使用,只能在类定义的方法中使用
  6. 访问构造器:this(参数列表);必须放置第一条语句

public class Test {    public static void main(String[] args) {        T t = new T();        System.out.println(t);    }}class T {    public T(){        this("jack"100);   // 这里面去访问T(String name, int age)构造器,this必须放在第一位        System.out.println("T() 构造器");    }    public T(String name, int age) {        System.out.println("T(String name, int age) 构造器");    }}
public void f3(){        String name = "smith";        // 传统方式        // 作用域:就近原则,如果此方法中有定义了就会直接访问此方法的数据        System.out.println("name=" + name + " num=" + num);        // 也可以使用this访问属性        // this直接访问本类的属性        System.out.println("name=" + this.name + " num=" + this.num);    }

四、第四部分

4.1 包

image-20210608170223736
image-20210608170223736

4.2 访问修饰符

基本介绍:

java提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):

  1. 公开级别:用public修饰,对外公开
  2. 受保护级别:用protected修饰,对子类和同一包中的类公开
  3. 默认级别:没有修饰符号,向同一个包的类公开
  4. 私有级别:用private修饰,只有类本身可以访问,不对外公开
访问级别 访问控制修饰符 同类 同包 子类 不同包
公开 public
受保护 protected ×
默认 没有修饰符 × ×
私有 private × × ×

4.3 封装介绍

封装就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作[方法],才能对数据进行操作

封装的好处

  1. 隐藏实现细节:方法(连接数据库)<--- 调用(传入参数...)
  2. 可以对数据进行验证,保证安全合理

封装的实现步骤

  1. 讲属性进行私有化private [不能直接修改属性]

  2. 提供一个公共的(public)set方法,用于对属性判断并赋值

    public void setXXX(类型 参数名){    // 加入数据验证的业务逻辑    属性 = 参数名;}
  3. 提供一个公共的get方法,用于获取属性的值

    public XX getXxx(){    return xx;}

封装是需要用private来修饰的,需要提供get和set方法,set没有返回值,gei有返回值,看你的需求

public class Test {    public static void main(String[] args) {        Person p1 = new Person();        p1.setName("张楠啊12312");//        p1.age = 18;        p1.setAge(180);        p1.setSalary(30000);        System.out.println(p1.toString());    }}class Person {    private String name;    private int age;    private  double salary;    public void setName(String name) {        // 对数据的校验        if(name.length() >= 2 && name.length() <= 6) {            this.name = name;        }else {            System.out.println("名字的长度不对,需要2-6个字符");            this.name = "无名人";        }    }    public void setAge(int age) {        if(age >= 1 && age <= 120){            this.age = age;        } else {            System.out.println("你设置的年龄不对,需要在1 - 120之间,给默认年龄18");            this.age = 18;        }    }    public int getAge(int age) {        return age;    }    public void setSalary(double salary) {        this.salary = salary;    }    public double getSalary(double salary) {        return salary;    }    @Override    public String toString() {        return "Person{" +                "name='" + name + '\'' +                ", age=" + age +                ", salary=" + salary +                '}';    }}

4.3.1 构造器set方法

如果封装之后没有在构造器中写set方法,那样的话安全机制不高,直接会绕过set方法,直接写一个构造器就会获取到数据,所以要把set方法写道构造器中

public class Test {    public static void main(String[] args) {        Person p1 = new Person("张楠"182300);//        p1.setName("张楠啊12312");//        p1.age = 18;//        p1.setAge(180);//        p1.setSalary(30000);        System.out.println(p1.toString());    }}class Person {    private String name;    private int age;    private  double salary;    // 构造器    public Person(String name, int age, double salary){        this.name = name;        this.age = age;        this.salary = salary;        setName(name);       // 把set方法写在构造器中        setAge(age);   // 把set方法写在构造器中        setSalary(salary);   // 把set方法写在构造器中    }    public void setName(String name) {        // 对数据的校验        if(name.length() >= 2 && name.length() <= 6) {            this.name = name;        }else {            System.out.println("名字的长度不对,需要2-6个字符");            this.name = "无名人";        }    }    public void setAge(int age) {        if(age >= 1 && age <= 120){            this.age = age;        } else {            System.out.println("你设置的年龄不对,需要在1 - 120之间,给默认年龄18");            this.age = 18;        }    }    public int getAge(int age) {        return age;    }    public void setSalary(double salary) {        this.salary = salary;    }        public double getSalary(double salary) {        return salary;    }    @Override    public String toString() {        return "Person{" +                "name='" + name + '\'' +                ", age=" + age +                ", salary=" + salary +                '}';    }}

4.5 继承

继承介绍

继承可以解决代码的复用,让我们的编程更加靠近人类思维,当多个类存在相同的方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可

继承的基本语法

class 子类 extends 父类{    // 代码}
image-20210611114617942
image-20210611114617942

代码示例:

// 这个类是[父类/基类/超类]public class Student {    public String name;    public int age;    public double score;    public void setScore(double score) {        this.score = score;    }    public void showInfo() {        System.out.println("学生名 " + name + " 年龄 " + age + " 成绩 " + score);    }}// 这个类是[子类/派生类]// 继承了Student类的属性和方法public class Pupil extends Student{    public void testing() {        System.out.println("小学生" + name + " 正在小学数学....");    }}// 这个类是[子类/派生类]// 继承了Student类的属性和方法public class Graduate extends Student{    public void testing() {        System.out.println("大学生" + name + " 正在大学数学....");    }}// 用主方法去调用public class Extends01 {    public static void main(String[] args) {        Pubil p1 = new Pubil();        p1.name = "银角大王~";        p1.age = 11;        p1.testing();        p1.setScore(50);        p1.showInfo();        System.out.println("-----" +                "--------------" +                "-------" +                "--");        com.day06.Graduate g1 = new Graduate();        g1.name = "金角大王~";        g1.age = 23;        g1.setScore(30);        g1.testing();        g1.showInfo();    }}

4.5.1继承的细节

  1. 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过公共的方法去访问
public class Base //父类    // 四个属性    public int n1 = 100;    protected int n2 = 100;    int n3 = 300;    private  int n4 = 400;    public Base() { // 无参构造器        System.out.println("base()....");    }        public void test100() {        System.out.println("test100");    }        protected void test200() {        System.out.println("test200");    }        void test300() {        System.out.println("test300");    }        private void test400() {        System.out.println("test400");    }     // 这个就是提供了一个公共的方法,去访问一个私有的方法    public void callTest400() {        test400();    }    // 返回一个N4,提供一个公共的方法,因为n4被private修饰了    public int getN4() {        return n4;    }}public class Sub extends Base{    public Sub() {        System.out.println("Sub()....");    }    public void sayOk() {        // 私有的属性和方法可以在子类直接访问        // 但是私有属性和方法不能在子类直接访问        System.out.println(n1 + " " + n2 + " " + n3 + " " + "n4" + " ");        test100();        test200();        test300();        // test400();        System.out.println("n4=" + getN4());//        System.out.println(callTest400());//        System.out.println("n4=");        callTest400();    }}public class ExtendsDetail {    public static void main(String[] args) {        Sub sub = new Sub();        sub.sayOk();    }}
  1. 当创建对象的时候必须调用父类的构造器,完成父类的初始化,默认调用父类的无参构造器super( )
public class Base //父类    // 四个属性    public int n1 = 100;    protected int n2 = 100;    int n3 = 300;    private  int n4 = 400;    public Base() { // 无参构造器        System.out.println("父类构造器base()....");    }}public class Sub extends Base{    public Sub() {        System.out.println("子类构造器Sub()....");    }}public class ExtendsDetail {    public static void main(String[] args) {        Sub sub = new Sub();        // sub.sayOk();    }}
  1. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super( )去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
  • 不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
public class Base //父类    // 四个属性    public int n1 = 100;    protected int n2 = 100;    int n3 = 300;    private  int n4 = 400;    public Base() { // 无参构造器        System.out.println("父类构造器base()....");    }}public class Sub extends Base{    public Sub() {        System.out.println("子类构造器Sub()....");    }}public class ExtendsDetail {    public static void main(String[] args) {        Sub sub = new Sub();    }}
  • 返回的结果
Base(String name, int age)构造器被调用....子类Sub()构造器被调用....Process finished with exit code 0
  • 默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super( )去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
public class Base //父类
    // 四个属性
    public int n1 = 100;
    protected int n2 = 100;
    int n3 = 300;
    private  int n4 = 400;
    
 // 把无参构造器注释掉
//    public Base() { // 无参构造器
//        System.out.println("父类base()构造器被调用....");
//    }
    public Base(String name, int age) {
        System.out.println("Base(String name, int age)构造器被调用....");
    }
    
}

public class Sub extends Base{
    public Sub() {
        // 因为父类没有无参构造器,所以要指定构造器,super() 必须放在第一行
        // super( ) 是调用父类的无参构造器
        super("smith",10);
        System.out.println("子类Sub()构造器被调用....");
    }
    public Sub(String name) {
        super("tom",10);
        System.out.println("子类Sub(String name)构造器被调用....");
    }
}

public class ExtendsDetail {
    public static void main(String[] args) {
        Sub sub = new Sub();
    }
}

子类只能继承一个父类,及java中是单继承机制

继承本质

image-20210613182857379
image-20210613182857379
  1. 首先看子类是否有该属性
  2. 如果子类有这个属性,并且可以访问,则返回消息
  3. 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息)
  4. 如果父类没有就按照(3)的规则,继续找上级父类,知道找到object
public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        System.out.println(son.name);
        System.out.println(son.getAge());
    }
}

class GrandPa // 爷类
    String name = "大头爷爷";
    String hobby = "旅游";
}

class Father extends GrandPa {
    String name = "大头爸爸";
    // 因为这个类提供了private修饰符
    private int age = 39;
    // 要提供一个get方法,才可以访问到
    public int getAge() {
        return age;
    }
}

class Son extends Father {
    String name = "大头儿子";
}

4.6 super关键字

super代表父类的引用,用于访问父类的属性,方法,构造器

4.6.1 super的基本语法

访问父类的属性,但不能访问父类的private属性 super.属性名

访问父类的方法,不能访问父类的private方法 super.方法名(参数列表)

访问父类的构造器:super(参数列表);只能放在构造器的第一句,只能出现一句

// 这个是A类
public class A {
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;
    public void test100() {

    }
    
    protected void test200() {

    }

    void test300() {

    }

    public void cal() {
        System.out.println("A类的cal() 方法....");
    }

    private void test400() {

    }
}

// 这个是B类
public class B extends A{
    // 访问父类的属性,但不能访问父类的private属性 super.属性名
    public void hi() {
        System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
    }
    
 // 访问父类的方法,不能访问父类的private方法 super.方法名(参数列表)
    public void ok() {
        super.test100();
        super.test200();
        super.test300();
    }
    
 // 访问父类的构造器:super(参数列表);只能放在构造器的第一句,只能出现一句
    public B() {
        // 访问父类的构造器
        super();
    }
}

4.6.2 super 和 this 的区别

No. 区别点 this super
1 访问属性 访问本类中的属性,如果本类没有此属性则从父类中继续查找 从父类开始查找属性
2 调用方法 访问本类中的方法,如果本类没有此方法则从父类继续查找. 直接访问父类中的方法
3 调用构造器 调用本类构造器,必须先放在构造器首行 调用父类构造器,必须放在子类构造器的首行
4 特殊 表示当前对象 子类中访问父类对象

4.7 方法的重载

方法覆盖(重写)override就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的那个方法

方法重写也叫方法覆盖,,需要满足一下条件

  1. 子类的方法的参数,方法名称,要和父类方法的参数,方法名完全一样
  2. 子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类,比如 父类 返回类型是Object,子类返回类型是String
  3. 子类方法不能缩小父类的访问权限
// 父类
public class Animal {
    public void cry() {
        System.out.println("动物叫唤...");
    }
    public Object m1() {
        return null;
    }
}

// 子类
public class Dog extends Animal{
    // 方法的重载
    public void cry() {
        System.out.println("小狗汪汪叫...");
    }
    // 方法的重载,父类的返回值类型是object类型的
    // 不可以缩小返回值的类型
    public String m1() {
        return null;
    }
}
名称 发生范围 方法名 形参列表 返回值类型 修饰符
重载(overload) 本类 必须一样 类型,个数或者顺序至少有一个不同 无要求 无要求
重写(override) 父子类 必须一样 相同 子类重写的方法,返回的类型和父类返回的类型一致,或者是其子类 子类方法不能缩小父类方法的访问范围

4.8 多态

多[多种]态[状态]基本介绍

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的

public class PloyMethod {
    public static void main(String[] args) {
        // 方法的重载体现多态
        A a = new A();
        System.out.println(a.sum(1020));
        System.out.println(a.sum(102030));
        // 方法的重写体现多态
        B b = new B();
        a.say();
        b.say();
    }
}
class B{
    public void say() {
        System.out.println("B say() 方法被调用....");
    }
}
class A extends B {
    public int sum(int n1, int n2) {
        return n1 + n2;
    }
    public int sum(int n1, int n2, int n3) {
        return n1 + n2 + n3;
    }
    public void say() {
        System.out.println("A say() 方法被调用.....");
    }
}

对象的多态

  1. 一个对象的编译类型和运行类型可以不一致
  2. 编译类型在定义对象时,就确定了,不能改变
  3. 运行类型时可以变化的
  4. 编译类型看定义时 = 号 的左边, 运行类型 = 号的 右边

案列:

Animal animal = new Dog();

[animal 编译类型是Animal,运行类型Dog]

国家一级抬杠运动员、

2021/06/15  阅读:73  主题:默认主题

作者介绍

国家一级抬杠运动员、