保姆级0基础学java之期末复习!

保姆级0基础学java之期末复习!

1.helloworld以及ideal的快捷键使用

package com.sxt;

import java.util.ArrayList;//导报

/**
 * Created with Intellij IDEA
 * Discripution:
 * User:ALL
 * Time:23:40
 */
public class hello {
    /*
       main方法 psvm
       System.out.println(""); 字面常量.sout
       ctrl+d 复制
       代码块的移动 ctrl+shift+上箭头/下箭头
       导包,生成变量 alt+enter
       单行注释/取消 ctrl+/
       多行注释/取消注释 ctrl+shift+/
       代码块包围 ctrl+alt+t
       构造方法,getter setter等等 alt+insert
     */
    public static void main(String[] args) {
        //1)String[] args数组的定义
        // 字符串类型 char*p="hello" 数组中存的都是字符串
        //数组是这样定义的
        //int arr[10] ->int[10] ->vs调试的时候arr int[10]
        for(int i=0;ijava test ljj is huaidan
        //                    java命令    运行时的命令行参数
        //2)sout
        System.out.println("7");//换行
        System.out.print("7");//不换行
        //用得最多的是前两个
        System.out.printf("%d\n",21);//如c语言
    }
}
/*多行注释
* 多行注释
* 不推荐 */
/**文档注释
 * 常用于方法和类上描述方法和类的作用
 * 可以被javadoc工具解析
 * 生成一套以网页文件形式体现的程序说明文档*/

java->javac .class->java运行
注意该字节码文件是一个类对应字节码文件

2.数据类型和变量

2.1常量

常量即程序运行期间,固定不变的量
字面常量的分类
1.字符串常量,“”
2.整形常量 直接写整数
3.浮点数常量 直接写小数
4.字符常量, ‘’
5.布尔常量 true false
6.空常量 null

左值=右值

2.2 数据类型

  • 数据类型
    • 基本数据类型(简单)
      • 整数 byte short int long
      • 小数 float double
      • 布尔值 boolean
      • 字符char
    • 引用数据类型
      • 数组 字符串 类 接口 枚举 String
  • 变量
    • 局部变量 在使用前一定要初始化
    • 成员变量

%将ideal中的项目直接部属到github上
保姆级0基础学java之期末复习!_第1张图片


表达式:变量和运算符构成的

数据类型占的byte:
在Java里面没有所谓无符号有符号注意的说法
保姆级0基础学java之期末复习!_第2张图片


public class TestDemo{
  public static void main(String[] args){
    System.out.println(Integer.MAX_VALUE);
    System.out.println(Integer.MIN_VALUE);
    int a = 10;
    long a = 10L;//10是长整形的类型 不加L会报错,小写l不推荐
    System.out.println(Long.MAX_VALUE);//9223372036854775807
    System.out.println(Long.MIN_VALUE);//-9223372036854775808
    short a = 10;
    System.out.println(Short.MAX_VALUE);//32767
    System.out.println(Short.MIN_VALUE);//-32768
    byte b1 =18;
    byte b2 =180;//报错
    //当Java使用=赋值一个字面值常量,超过范围后会自动检查字面值常量,斌且识别为int类型
    System.out.println(Byte.MAX_VALUE);//127
    System.out.println(Byte.MIN_VALUE);//-128
    float f =12.5f;//如果不加f会默认12.5是一个double类型
    //遵循c中float的存储
    //包装类Float 不研究最大值最小值
    System.out.println(Float.MAX_VALUE);
    System.out.println(Float.MIN_VALUE);
    char ch = '搞';
    System.out.println(ch);
    //java里面用unicode表示字符
    //用记事本出现中文会有编码错误javac -encoding UTF-8 xxx.java
  }
}

Integer 叫包装类 包装类即基本数据类型所对应的类类型
int —>interger[int的plus版本]
long 8个字节->数值:63bit -2^63 ~ (2^63)-1
short 2个字节->数值:15bit -2^15 ~ (2^15)-1
byte 1个字节 ->数值—:7bit -2^7 ~ (2^7)-1
float 4个字节
double 8个字节 双精度
char 2个字节 ->对应地包装类Character
boolean 可能8bit ->Boolean

保姆级0基础学java之期末复习!_第3张图片

布尔变量boolean
JVM中没有指定布尔元素大小

但是说boolean数组在JVM地实现中,Java编程语言中地布尔数组被编码成JVM字节数组,每个布尔元素使用8位
没有谱所谓地非0为真 0为假

  int a = 1;if(a){;}//报错
  if(a!=0){;}//正确 

3.类型转换

显示隐

  pubic class TestDemo{
    public static void main(String[] args){
      int a = 10;
      long b = 20;
      int c = a + b;//编译错误 a + b==>int + long --> long + long 赋值给int会丢失数据
      int c = (int)(a+b);//强制类型转换
      long d = a + b;//编译成功 int+long --->long + long赋值给long
    }
  }

由于cpu是按照4个字节为单位从内存中读取数据,byte short这种低于四个字节地类型 会提升成int再计算

4.string

+是拼接地意思 只要和字符串拼接就直接是字符串 不会进行运算

public class TestDemo{
 public static void main(String[] args)
    {
        String st1 = "男神";
        String st2 = "爱我";
        System.out.println(st1+st2);
        int a = 10;
        int b = 20;
        System.out.println("a="+a+"b="+b);
        System.out.println("a+b=" +a+b);//都是字符串拼接
        System.out.println("a+b="+(a+b));
        System.out.println(a+b+"->a+b");//开始是整数后面字符串拼接
        /*a=10b=20
        a+b=1020
        a+b=30
        30->a+b*/
    }
}

4.1 int与string互相转换

public class TestDemo{
 public static void main(String[] args) {
        //int转string
        int num=1;
        String str1=num+"";//法1
        System.out.println(str1);//1
        String str2=String.valueOf(num);//法2
        System.out.println(str2);//1
        //String转int
         String str = "100";
        int sum=Integer.parseInt(str);
        System.out.println(sum);//100
    }
}

5.运算符

5.1. 基本四则运算符:加减乘除模(+ - * / %)

注意:
都是二元运算符,使用时必须要有左右两个操作数
int / int 结果还是int类型,而且会向下取整

int a = 10;
int b = 20;
a + b;
a < b;
int a = 20;
int b = 10;
System.out.println(a + b); // 30
System.out.println(a - b); // 10
System.out.println(a * b); // 200
System.out.println(a / b); // 2
System.out.println(a % b); // 0 --->模运算相当于数学中除法的余数

保姆级0基础学java之期末复习!_第4张图片

  • 做除法和取模时,右操作数不能为0
  • % 不仅可以对整形取模,也可以对double类型取模,但是没有意义,一般都是对整形取模的
System.out.println(11.5 % 2.0);
// 运行结果1.5
  • 两侧操作数类型不一致时,向类型大的提升
System.out.println(1+0.2); // +的左侧是int,右侧是double,在加之前int被提升为double
// 故:输出1.2

5.2移位操作符

  1. 左移 1 位, 相当于原数字 * 2. 左移 N 位, 相当于原数字 * 2 的N次方.<<
  2. 右移 1 位, 相当于原数字 / 2. 右移 N 位, 相当于原数字 / 2 的N次方.>>
  3. 由于计算机计算移位效率高于计算乘除, 当某个代码正好乘除 2 的N次方的时候可以用移位运算代替.
  4. 移动负数位或者移位位数过大都没有意义.

方法签名:经过编译器修改之后最终的方法名字
方法全路径名+参数列表+返回值类型
保姆级0基础学java之期末复习!_第5张图片

关于调用栈
方法调用的时候,会有一个栈这样的内存空间描述当前的调用关系,称为调用栈
每一次方法的调用就称为一个栈帧,每一个栈帧中包括了这次调用的参数是哪些,返回哪里等消息
可以借用idea看到

保姆级0基础学java之期末复习!_第6张图片

基本数据创建的变量叫做基本变量,其变量空间存储的是所对应的值,
引用数据创建的变量叫做对象的引用,存贮的是对象所在空间地址

  public static void func() {
int a = 10;
int b = 20;
int[] arr = new int[]{1,2,3};
}

在上述代码中,a、b、arr,都是函数内部的变量,因此其空间都在main方法对应的栈帧中分配。
a、b是内置类型的变量,因此其空间中保存的就是给该变量初始化的值。
array是数组类型的引用变量,其内部保存的内容可以简单理解成是数组在堆空间中的首地址。

array1=array2;

让array1去引用array2引用的空间,此时array1和array2完全是一个数组。

在方法中修改参数的值(基础数据),不影响实参的值。
修改引用数据类型的值,会影响实参的值

5.2.1总结:

所谓的 “引用” 本质上只是存了一个地址. Java 将数组设定成引用类型, 这样的话后续进行数组参数传参, 其实只
是将数组的地址传入到函数形参中. 这样可以避免对整个数组的拷贝(数组可能比较长, 那么拷贝开销就会很大).

有些知识点和c++没差 我就不写了哈 感觉好啰嗦 摆烂

6.构造方法

public class Date {
        public int year;
        public int month;
        public int day;
        //无参构造方法--内部给各个成员赋值初始值,该功能与三个参数的构造方法重复
        //此处可以在无参构造方法中通过this调用带有三个参数的构造方法
        //但是this(1900,1,1);必须是构造方法中第一条语句
        public Date(){
            this(1900,1,1);
            //this.year=1900;
            //this.month=1;
            //this.day=1;
        }
        public Date(int year,int month,int day){
            this.year=year;
            this.month=month;
            this.day=day;
        }
        public static void mian(String[] args){

        }
}

this(…)必须是构造方法中第一条语句
不能形成环

public Date(){
this(1900,1,1);
}
public Date(int year, int month, int day) {
this();
}
/*
无参构造器调用三个参数的构造器,而三个参数构造器有调用无参的构造器,形成构造器的递归调用
编译报错:Error:(19, 12) java: 递归构造器调用
*/

6.1默认初始化

有个疑惑:局部变量必须要初始化才能使用,为什么字段声明之后没有给值依然可以使用?

public class Date {
public int year;
public int month;
public int day;
public Date(int year, int month, int day) {
// 成员变量在定义时,并没有给初始值, 为什么就可以使用呢?
System.out.println(this.year);
System.out.println(this.month);
System.out.println(this.day);
}
public static void main(String[] args) {
// 此处a没有初始化,编译时报错:
// Error:(24, 28) java: 可能尚未初始化变量a
// int a;
// System.out.println(a);
Date d = new Date(2021,6,9);
}
}

要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情:

Date d = new Date(2021,6,9);

在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:

  1. 检测对象对应的类是否加载了,如果没有加载则加载
  2. 为对象分配内存空间
  3. 处理并发安全问题
    比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突
  4. 初始化所分配的空间
    即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值,比如:
数据类型 默认值
byte 0
char ‘\u0000’
short 0
int 0
long 0L
boolean false
float 0.0f
double 0.0
reference null
  1. 设置对象头信息(关于对象内存模型后面会介绍)

  2. 调用构造方法<>,给对象中各个成员赋值

6.2就地初始化

public class Date {
public int year = 1900;
public int month = 1;
public int day = 1;
public Date(){
}
public Date(int year, int month, int day) {
}
public static void main(String[] args) {
Date d1 = new Date(2021,6,9);
Date d2 = new Date();
}
}

代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中

7.封装

7.1访问限定符

Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认
知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:
保姆级0基础学java之期末复习!_第7张图片

protected主要是用在继承中,继承部分详细介绍
default权限指:什么都不写时的默认权限
访问权限除了可以限定类中成员的可见性,也可以控制类的可见性

7.2封装扩展之包

在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。有点类似于目录。比如:为了更好的管理电脑中的歌曲,一种好的方式就是将相同属性的歌曲放在相同文件下,也可以对某个文件夹下的音乐进行更详细的分类。
在Java中也引入了包,包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一个包中的类不想被其他包中的类使用。包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。


例如:使用java.util.Date导入java.util这个包中的Date类


    public static void main(String[] args) {
        java.util.Date data=new java.util.Date();
        //得到一个毫秒级别的时间
        System.out.println(data.getTime());
    }

直接import语句导入一个具体的类,不能导入一个具体的包

import java.util.Arrays;//需要导入一个具体的类
import java.util;//不能导入一个具体的包
import java.util.Date;
public class{
    public static void main(String[] args) {
        Date data=new Date();
        System.out.println(data.getTime());
    }
}

引用java.util.这个包其中的其他类时
虽然但是还是推荐显示的使用,因为还是会发生冲突(包中类的方法相同)

import java.util.*;//这个表示导入util中所有的类,但是会冲突
public class Test {
  public static void main(String[] args) {
    Date date = new Date();
    // 得到一个毫秒级别的时间戳
    System.out.println(date.getTime());
  }
}

所以下面这种情况下需要写完整类名

import java.util.*;//通配符
import java.sql.*;
public class Test {
public static void main(String[] args) {
java.util.Date date = new java.util.Date();
System.out.println(date.getTime());
}
}

可以使用import static导入包中静态的方法和字段。
lang下的包System的out属性

import static java.lang.Math.*;
import static java.lang.System.*;
public class Test {
public static void main(String[] args) {
  //System.out.println("fasfa");
  //直接可以省略System,写out
  //用得少
  out.println("fsfsdga");
  //又例如
  out.println(Math.max(10,20));
  //max是类名去调用的静态方法
  //所以开头加入
  //import static java.lang.Math.*;
  //out.println(max(10,20))
  double x = 30;
  double y = 40;
  // 静态导入的方式写起来更方便一些.
  // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  double result = sqrt(pow(x, 2) + pow(y, 2));
  System.out.println(result);
  }
}

包是组织类的一种形式,使用包是为了保证类的唯一性

import 和 C++ 的 #include 差别很大. C++ 必须 #include 来引入其他文件内容, 但是 Java 不需要.
import 只是为了写代码的时候更方便. import 更类似于 C++ 的 namespace 和 using

7.2 自定义包

包实际是一个文件夹 src放的源代码
包名必须是小写字母

  1. 在 IDEA 中先新建一个包: 右键 src -> 新建 -> 包
    保姆级0基础学java之期末复习!_第8张图片

  2. 在弹出的对话框中输入包名, 例如 com.bit.demo1

  3. 在包中创建类, 右键包名 -> 新建 -> 类, 然后输入类名即可

  4. 此时可以看到我们的磁盘上的目录结构已经被 IDEA 自动创建出来了
    保姆级0基础学java之期末复习!_第9张图片

  5. 同时我们也看到了, 在新创建的 Test.java 文件的最上方, 就出现了一个 package 语句
    保姆级0基础学java之期末复习!_第10张图片

注意:

7.3 包访问限定符

private包访问权限-》只能在当前包中使用,当你的成员变量不加任何访问修饰限定词的时,默认使用
保姆级0基础学java之期末复习!_第11张图片
保姆级0基础学java之期末复习!_第12张图片
保姆级0基础学java之期末复习!_第13张图片

这是由于这两个类是在同一个包底下
所以test类不能在不同包中使用 即使import导入包中的类

常见的系统包

  1. java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。不需要import导入
  2. java.lang.reflect:java 反射编程包;
  3. java.net:进行网络编程开发包。
  4. java.sql:进行数据库开发的支持包。
  5. java.util:是java提供的工具程序包。(集合类等) 非常重要
  6. java.io:I/O编程开发包。

几个问题:

保姆级0基础学java之期末复习!_第14张图片
保姆级0基础学java之期末复习!_第15张图片
保姆级0基础学java之期末复习!_第16张图片


8.继承(is a)

保姆级0基础学java之期末复习!_第17张图片
保姆级0基础学java之期末复习!_第18张图片
保姆级0基础学java之期末复习!_第19张图片

其中:Animal类称为父类/基类或超类,Dog和Cat可以称为Animal的
子类/派生类,继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。

语法规则

  1. Java是单继承,不能同时继承两个及两个以上的类。(c++可以多继承)
  2. 子类会继承父类的所有public方法和字段;对于父类的private的字段和方法,子类中是无法访问的
  3. 子类构造的同时要帮助父类来进行构造
  4. 子类的实例中,也包含着父类的实例,可以使用super关键字得到父类实例的引用

8.1父类成员的访问

8.1.1子类父类成员变量不同名

保姆级0基础学java之期末复习!_第20张图片

8.1.2子类父类成员变量同名

保姆级0基础学java之期末复习!_第21张图片

class A{
    int a=10;
}
class B extends A{
    char a ;
    public void func(){
        a=97;//char类型可以用整数接收
    }
    //仍然满足就近原则 优先子类自己的
    //即子类将父类同名成员隐藏了
}
public class TestDemo {
    public static void main(String[] args) {
     B b = new B();
     b.func();
     System.out.println(b.a);//输出为a
    }
}

如何换用父类

class A{
    int a=10;
}
class B extends A{
    char a ;
    public void func(){
        super.a=97;
    }//引用父类的a,所以此时char a没有定义
}
public class TestDemo {
    public static void main(String[] args) {
     B b = new B();
     b.func();
     System.out.println(b.a);//输出空字符
     A a = new A();
     System.out.println(a.a);//输出10
    }
}

8.2.super关键字

8.2.1 super和this区别

【相同点】

  1. 都是Java中的关键字

  2. 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
    保姆级0基础学java之期末复习!_第22张图片

  3. 在构造方法中调用时,必须是构造方法的第一行,所以super()与this()不能同时存在

【不同点】

  1. this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用
    保姆级0基础学java之期末复习!_第23张图片

  2. 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性

  3. this是非静态成员方法的一个隐藏参数,super不是隐藏的参数

  4. 成员方法中直接访问本类成员时,编译之后会将this还原,即本类非静态成员都是通过this来访问的;在子类
    中如果通过super访问父类成员,编译之后在字节码层面super实际是不存在的(通过字节码文件可以验证)
    保姆级0基础学java之期末复习!_第24张图片

  5. 构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有

8.3.再谈初始化

class Animal{
    public String name;
    public int age;
    //执行顺序:先静态后实例后构造方法
    static{
        System.out.println("这是Animal的静态代码块");
    }

    {
        System.out.println("这是Animal的实例代码块");
    }

    public Animal(String name, int age){
        this.name=name;
        this.age=age;
        System.out.println("Animal带两个参数的构造方法");
    }

    public Animal() {
        name="子类无参优先帮助父类构造";
        age=889;
        System.out.println("Animal不带参数的构造方法");
    }
}
class Cat extends Animal{
    public float weight;

    static{
        System.out.println("这是cat的静态代码块");
    }

    {
        System.out.println("这是cat的实例代码块");
    }

    public Cat(){
        super();
        //name="dada";
        //age=12;
        //子类优先
        weight=2;
        System.out.println("不带参数的构造方法");
    }

    public Cat(String name, int age,float weight){
        super(name,age);
        this.weight=weight;
        System.out.println("cat带三个参数的构造方法");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Cat cat=new Cat("kk",11,2);
        //cat.show();

        System.out.println("======");
        Cat cat2=new Cat("mm",11,22);
    }
}

[输出结果]

这是Animal的静态代码块
这是cat的静态代码块
这是Animal的实例代码块
Animal带两个参数的构造方法
这是cat的实例代码块
cat带三个参数的构造方法
======
这是Animal的实例代码块
Animal带两个参数的构造方法
这是cat的实例代码块
cat带三个参数的构造方法

通过分析执行结果,得出以下结论:
1、父类静态代码块优先于子类静态代码块执行,且是最早执行
2、父类实例代码块和父类构造方法紧接着执行
3、子类的实例代码块和子类构造方法紧接着再执行
4、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行

8.4protected关键字

保姆级0基础学java之期末复习!_第25张图片
保姆级0基础学java之期末复习!_第26张图片

保姆级0基础学java之期末复习!_第27张图片

父类中private成员变量虽然在子类中不能直接访问,但是也继承到子类中了

什么时候下用哪一种呢?
我们希望类要尽量做到 “封装”, 即隐藏内部实现细节, 只暴露出 必要 的信息给类的调用者.
因此我们在使用的时候应该尽可能的使用 比较严格 的访问权限. 例如如果一个方法能用 private, 就尽量不要
用 public.
另外, 还有一种 简单粗暴 的做法: 将所有的字段设为 private, 将所有的方法设为 public. 不过这种方式属于是
对访问权限的滥用, 还是更希望同学们能写代码的时候认真思考, 该类提供的字段方法到底给 “谁” 使用(是类内
部自己用, 还是类的调用者使用, 还是子类使用).

8.5final关键字

可修饰变量,成员方法以及类

  1. 修饰变量或字段,表示常量(即不能修改)

final int a = 10;
a = 20; // 编译出错

  1. 修饰类:表示此类不能被继承

final public class Animal {

}
public class Bird extends Animal {

}
// 编译出错
Error:(3, 27) java: 无法从最终com.bit.Animal进行继承

  1. 修饰方法:表示该方法不能被重写

9. 组合

class Money{

}
class Student{
        public Money money=new Money();
}
class Teacher{
        public Money money;//复用money类中的属性和方法
}
class School{
        public Money money;
        public Teacher[] teacher;
        public Student[] student;
}

10.多态

10.1向上转型

父类对象引用子类

实际上就是创建一个子类对象,将其当作父类对象来使用

父类类型 对象名 =new 子类类型
Animal animal=new Cat(“姐姐”,2);

animal是父类类型,但是可以引用一个字类类型,因为是从小范围到大范围的转换。

三种常见的父类转型

  1. 直接赋值
  2. 方法传参
  3. 方法返回

1.直接赋值

class Animal{
    public String name;
    public int age;
    public void eat(){
        System.out.println(this.name+"eat");
    }
}
class Cat extends Animal{
    public String hair;
    public void mew(){
        System.out.println(this.name+"mew");
    }
}
public class TestDemo {
        public static void main2(String[] args) {
        //Cat cat = new Cat();
        //Animal animal = cat;//父类的引用可以引用子类的对象
        //合并成一句话
        Animal animal = new Cat();//向上转型
        //animal.hair="wqe";错误
        animal.name="kk ";
        animal.eat();
        //animal.mew();错误 不可以访问 只能访问父类自己特有的成员
    }
    public static void main1(String[] args) {
        Cat cat=new Cat();
        cat.mew();
        cat.eat();

        Animal animal = new Animal();
        animal.eat();//这里通过父类引用 只能访问父类自己的方法
    }
}

2.方法传参

public class TestDemo {
    public static void func(Animal animal){

    }

    public static void main(String[] args) {
        //Cat cat = new Cat();
        //func(cat);
        //或者
        func(new Cat());
    }
}

3.方法返回

public class TestDemo {
  public static Animal func(){
    //return new Animal();
    //或者
    return new Cat();
    //此就是应用了向上转型,子类对象当成父类对象来使用
    }
}

向上转型的优点:让代码实现更简单灵活。
向上转型的缺陷:不能调用到子类特有的方法

10.2 向下转型

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换

向下转型引用对象 = (转型的类型)父类引用;
父类引用 instanceof 转型类型

public static void main(String[] args) {
        Animal animal = new Cat();//向上转型
        //由于向下转型不安全,不能确定该引用对象是不是Bird类的实例化对象
        //即猫不是鸟
        //instanceof ::用来检查向下转型是否安全,不安全返回false
        if (animal instanceof Bird) {
            Bird bird = (Bird) animal;//向下转型
            bird.fly();
        }
    }

#3# 10.3 方法重写

class Animal{
    public String name="动物";
    public int age;
    public void eat(){
        System.out.println(this.name+"吃饭");
    }
}
class Cat extends Animal{
    public String hair;
    public void eat(){
        System.out.println("mao吃猫粮");
    }

    public void mew(){
        System.out.println(this.name+"mew");
    }
}

public class TestDemo {
    public static void main(String[] args) {
        Animal animal = new Cat();
        animal.eat();//实际上编译的还是这里还是Animal的eat()方法
    }
}

运行结果:
animal调用的是子类的方法
但是此时任然不能访问mew(),父类没有

保姆级0基础学java之期末复习!_第28张图片
保姆级0基础学java之期末复习!_第29张图片

为什么会调用子类的呢?
实际上编译的animal.eat()还是Animal的eat()方法

找到字节码文件目录,用PowerShell打开字节码文件进行编译
保姆级0基础学java之期末复习!_第30张图片

使用命令行语句:

javap -c 类名
保姆级0基础学java之期末复习!_第31张图片

但是在运行的时候就变成了子类自己的eat(),运行时绑定,在运行时才确定要绑定谁,称动态绑定;
静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。
动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。

10.4重写/覆盖/覆写

要求

  1. 方法名相同
  2. 参数列表相同
  3. 返回值类型相同

注意

  1. 父类被static、private final修饰的方法都不能被重写
  2. 子类的访问修饰限定符要大于等于父类的
  3. 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
  4. 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。(实际上就是包访问权限)
  5. 重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法
    构成重写.
  6. JDK7以后,被重写的方法返回值类型可以不同,但是必须是具有父子关系的

协变类型
比如返回值类型构成父子关系

保姆级0基础学java之期末复习!_第32张图片

10.5多态

具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
在java中要实现多态,必须要满足如下几个条件,缺一不可:

  1. 向上转型:父类引用 引用子类对象
  2. 发生重写: 父类和子类当中有同名的覆盖方法
  3. 通过父类的引用,调用这个同名的方法:此时会发生动态绑定思想:同一个方法,因为调用这个方法的引用,引用的子类对象不同,所执行的行为也是不一样的
 public static void function(Animal animal){
        animal.eat();
    }
public static void main(String[] args) {
        Cat cat = new Cat();
        Dog dog = new Dog();
        function(cat);
        function(dog);
}

避免在构造方法中调用重写的方法

class B {
  public B() {
    // 此时也会发生动态绑定,转为调用子类的func方法
    func();
 }
  public void func() {
    System.out.println("B.func()");
 }
}
class D extends B {
  private int num = 1;
  D(){
      super();
  }
  @Override
  public void func() {
    System.out.println("D.func() " + num);
 }
}
public class Test {
  public static void main(String[] args) {
    D d = new D();
    }
}

执行结果:
D.func() 0

分析:
构造d对象的同时会调用父类的构造方法
b的构造方法中还调用了func方法,此时会触发动态绑定,会调用到d中的func
此时d对象自身还没有完成构造,所以num处于未初始化的状态,值为0;

结论: “用尽量简单的方式使对象进入可工作状态”, 尽量不要在构造器中调用方法(如果这个方法被子类重写, 就会触
发动态绑定, 但是此时子类对象还没构造完成), 可能会出现一些隐藏的但是又极难发现的问题.

11.抽象类

//抽象类
abstract class Shape{
    public abstract void draw();//抽象方法
}
class Cycle extends Shape{
    //当一个普通的类,继承了这个抽象类之后,那么这个普通类必须重写这个抽象类当中的所有抽象方法
    @override
    public void draw(){
        System.out.println("00");
    }
}
//当一个抽象类A继承了抽象类B,此时抽象类不必要重写抽象类B中的方法
abstract class A extends Shape{
    public abstract void func();
}
//当一个普通类接着继承,此时就得重写所有的抽象方法
class C extends A{
    @Override
    public void func() {

    }

    @Override
    public void draw() {

    }
}
public class TestDemo {
    public static void main(String[] args) {
        //抽象类不能实例化
        //Shape shape = new Shape();错误
        
         //抽象类存在的最大意义就是额为了被继承
         //且抽象类必须被继承
        //所以抽象类也可以发生向上转型,进一步发生多态
        Shape shape = new Cycle();
    }
}

唯一的和普通类的区别就是被abstract修饰,不能进行实例化

注意:

  1. 抽象类不能是private,没有加访问限定修饰符的时候默认是public
  2. 抽象方法不能被final和static修饰,因为抽象方法要被子类重写
  3. 抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也i是抽象类,也要被abstract修饰
  4. 抽象类中不一定要包含抽象方法,但是有抽象方法的类一定是抽象类
  5. 抽象类中可以有构造方法,方便供子类创建对像的时候初始化父类对象

【抽象类的作用】
抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.
有些同学可能会说了, 普通的类也可以被继承呀, 普通的方法也可以被重写呀, 为啥非得用抽象类和抽象方法
呢?
确实如此. 但是使用抽象类相当于多了一重编译器的校验.
使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类
了, 使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题.
很多语法存在的意义都是为了 “预防出错”, 例如我们曾经用过的 final 也是类似. 创建的变量用户不去修改, 不
就相当于常量嘛? 但是加上 final 能够在不小心误修改的时候, 让编译器及时提醒我们.
充分利用编译器的校验, 在实际开发中是非常有意义。

12.接口

接口就是公共的行为规范标准,大家在实现时,只要符合规范标准,就可以通用。
在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。
2.2 语法规则
接口的定义格式与定义类的格式基本相同,将class关键字换成 interface 关键字,就定义了一个接口。

interface IShape{
    //成员变量 默认为public static final
    public static final int a = 10;
    //成员方法 默认为public abstract
    public abstract void draw();
    //接口当中的方法,如果要实现,需要用default来修饰
    default void func(){
        System.out.println("默认的方法");
    }
    //接口当中静态的方法可以有具体的实现
    public static void staticFunc(){
        System.out.println("静态方法");
    }
}
//接口被继承 implement
//重写接口的方法
//一个普通的类可以通过implement来实现这个接口
// 需要重写抽象方法,覆盖父类的
// 也可以重写默认方法
class A1 implements IShape {
    @Override
    public void draw() {
        System.out.println("子类继承后重写的方法");
    }
}


public class Tst {
    //接口可以实现向上转型,也可以实现多态
    public static void drawMap(IShape shape){
        shape.draw();
    }
    public static void main(String[] args) {
        //接口不能进行实例化,只能被继承
        //IShape iShape = new IShape();
        IShape iShape = new A1();
        iShape.draw();
        iShape.func();
        IShape.staticFunc();
        IShape iShape1 = new A1();
        drawMap(iShape1);
    }
}

提示:

  1. 创建接口时, 接口的命名一般以大写字母 I 开头.
  2. 接口的命名一般使用 “形容词” 词性的单词.
  3. 阿里编码规范中约定, 接口中的方法和属性不要加任何修饰符号, 保持代码的简洁性.

接口不能直接使用,必须要有一个"实现类"来"实现"该接口,实现接口中的所有抽象方法。

public class 类名称 implements 接口名称{
// …
}

注意:子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系。
注意:子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系。

12.1接口的特性

(一个接口一个Java文件 一个类一个Java文件)

  1. 接口类型是一种引用类型,但是不能直接new接口的对象//是抽象的; 无法实例化
  2. 接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract(只能是
    public abstract,其他修饰符都会报错)
  3. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现
    //因为接口中的方式默认为抽象方法
    接口抽象方法不能带有主体
  4. 重写接口中抽象方法时,不能使用default访问权限修饰,不能使用默认修饰符public
  5. 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量
  6. 接口中不能有静态代码块和构造方法
  7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
  8. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
  9. jdk8中:接口中还可以包含default方法。

12.2 实现多个接口

一个类可以继承抽象类,同时实现多个接口,每个接口之间使用逗号隔开
为什么接口的出现解决了多继承的问题?
接口可以相当于一个特性 只要是参数,具备该种特性就可以用implement实现接口

class Animal{
    public String name;
    public int age;
    public Animal(String name){
        this.name = name;
    }
    public void eat(){
        System.out.println(this.name+"吃饭");
    }
//不能把飞 跑 游泳这些操作 写道父类(标准)中去
}
interface IFlying{
    public abstract void fly();
}
interface IRunning{
    void run();
}
interface ISwimming{
    void swim();
}
//狗继承动物实现跑 游泳接口 同时也必须重写接口中所有的抽象方法
class Dog extends Animal implements IRunning,ISwimming{
    public Dog (String name){
        super(name);
    }

    @Override
    public void run() {
        System.out.println("狗跑步");
    }
    @Override
    public void swim(){
        System.out.println("狗游泳");
    }
}
//1.构造方法需要调用父类方法·实例化(构造)猫这个类型
class Cat extends Animal implements IRunning{
    public Cat (String name){
        super(name);
    }

    @Override
    public void run() {
        System.out.println("猫跑步");
    }
}
public class Test2 {
    public static void walk(IRunning iRunning){
        iRunning.run();
    }
    public static void main(String[] args) {
    walk(new Dog("ww"));
    walk(new Cat("mi"));
    }
    public static void main1(String[] args) {
        Animal animal  = new Cat("mi");
        Animal animal2 = new Dog("wang");

        IRunning iRunning = new Dog("wangwang");
        IRunning IRunning2 = new Cat("mimi");

        ISwimming swimming = new Dog("nini");

    }
}

12.3接口间的继承

interface W{
    void  funcW();
}

interface M{
    void funcM();
}
interface N extends W,M{
    void funcN();
}
//或者直接在这前面加abstract就不需要全部重写抽象函数 但是当另一个类再次继承ww时候必须全部重写抽象函数
class WW implements N{

    @Override
    public void funcW(){
        System.out.println("jiejie");
    }

    @Override
    public void funcM() {
        
    }

    @Override
    public void funcN() {
        
    }
}

java interface Comparrable;

在这里插入图片描述

12.4几个重要的接口

package com.sxt.demo3;
import java.util.Arrays;

import java.util.Comparator;

/**
 * Created with Intellij IDEA
 * Discripution:3个重要的接口
 * User:ALL
 * Date:2022-05-S{DAY}
 * Time:20:56
 */
//comparable接口
//相当于将每个对象强转于comparable,comparable中的函数只有compareTo;
//即将每个对象的其它信息隐藏只留下compareTo中指定的属性来进行比较
//
class Student i/*mplements Comparable*/ {
    public String name;
    public int age;
    public double score;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" + "name=" + name + '\'' +
                ",age=" + age + "\'" +
                ",score=" + score + "}";
    }
  /*  @Override
    public int compareTo(Student o) {
        return this.name.compareTo(o.name);
        //return this.age-o.age;

    }*/
}//
//comparator接口
//comparable接口只能一个一个的重新比较
//comparator接口可以由多个对象继承。每个对象的属性都可以重写接口

//*问题 为什么不需要实现comparator接口不用重写equals抽象方法?
//一个类扩展了一个超类,同时实现了一个接口,并从超类和接口继承了相同的方法,
// 在这种情况下,只会考虑超类的方法,接口无论是否提供默认方法都会被忽略,这正是“类优先”规则。
//equals方法在Object超类中有(已实现),在Comparator接口中也有(未实现),
// 所以一个类实现Comparator接口(实际隐含继承Object超类),
// 故根据“类优先”规则,会忽略Comparator接口中的equals方法,故而只需实现compare方法即可。

//比较器
class AgeComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2){
        return o1.age-o2.age;
    }
}
class StringComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1,Student o2){
        return o1.name.compareTo(o2.name);
    }
}
class ScoreComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1,Student o2){
        return (int) (o1.score-o2.score);
    }
}
public class Tesr {
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("syh", 22, 9);
        students[1] = new Student("sh", 2, 8);
        students[2] = new Student("s", 0, 7);
        /*System.out.println(students[0].compareTo(students[1]));
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));*/
        //java中无法通过大于小于号来引用对象进行比较
        //if(students[0]>students[1])
        //*Java中的引用类型比较大小的前提,
        //1.可以比较
        //2.重写某种方法(重写compareTo或者比较器中的compare方法)
        //this.compareTo.o
        //students[0].compareTo(students[1])
        System.out.println("排序前"+Arrays.toString(students));
        AgeComparator agecomparetor = new AgeComparator();
        StringComparator stringComparator=new StringComparator();
        Arrays.sort(students,stringComparator);
        //public static  void sort(     @NotNull T[] a,
        //    @Nullable java.util.Comparator 0
        System.out.println("排序后"+Arrays.toString(students));
    }
    public static void main1(String[] args) {
        int[] Arr = {1,222,43,42};
        Arrays.sort(Arr);
        System.out.println(Arrays.toString(Arr));
    }
}

12.5 Clonable接口和深拷贝

保姆级0基础学java之期末复习!_第33张图片

package com.sxt.demo4;

/**
 * Created with Intellij IDEA
 * Discripution:clonable接口和深拷贝
 * User:ALL
 * Date:2022-05-S{DAY}
 * Time:17:27
 */
class Money{
 public double money = 19.9;
}
//拷贝数组
//person1引用所指的对象是id,现在要拷贝对象,克隆方法
class Person implements Cloneable{
    //基本类型
    public int id =1234;
    //引用类型
    public Money M = new Money();
    @Override
    public String toString(){
        return "id:"+id;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException{
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1=new Person();
        //*拷贝对象前提
        //1.这个对象可以被克隆
        //2.自定义类型被克隆需要实现Cloneable接口
        //没有new对象,是克隆出来的,会产生一个所指对象的副本(地址不同)
        Person person2=(Person)person1.clone();
        System.out.println(person1.M.money);//19.9
        System.out.println(person2.M.money);//19.9
        System.out.println("=====");
        person1.M.money=99.9;
        System.out.println(person2.M.money);//99.9
        System.out.println(person2.M.money);//99.9
    }
}

保姆级0基础学java之期末复习!_第34张图片
保姆级0基础学java之期末复习!_第35张图片

class Money implements Cloneable{
 public double money = 19.9;
 @Override
    public Object clone() throws CloneNotSupportedException{
     return super.clone();
 }
}
//拷贝数组
//person1引用所指的对象是id,现在要拷贝对象,克隆方法
class Person implements Cloneable{
    //基本类型
    public int id =1234;
    //引用类型
    public Money M = new Money();
    @Override
    public String toString(){
        return "id:"+id;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException{
        //浅拷贝
        // return super.clone();
        //深拷贝
         Person tmp=(Person)super.clone();
         tmp.M=(Money)this.M.clone();
         return tmp;
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1=new Person();
        //*拷贝对象前提
        //1.这个对象可以被克隆
        //2.自定义类型被克隆需要实现Cloneable接口
        //没有new对象,是克隆出来的,会产生一个所指对象的副本(地址不同)
        Person person2=(Person)person1.clone();
        System.out.println(person1.M.money);//19.9
        System.out.println(person2.M.money);//19.9
        System.out.println("=====");
        person2.M.money=99.9;
        System.out.println(person1.M.money);//浅:99.9 深:19.9
        System.out.println(person2.M.money);//99.9
    }
}

保姆级0基础学java之期末复习!_第36张图片

实现深拷贝 是从代码层次上进行的,不是说某个方法是深拷贝,而是从代码的实现上来看的

this.name.equals(Student.name);
保姆级0基础学java之期末复习!_第37张图片

保姆级0基础学java之期末复习!_第38张图片

class Money implements Cloneable{
 public double money = 19.9;
 @Override
    public Object clone() throws CloneNotSupportedException{
     return super.clone();
 }
}
//拷贝数组
//person1引用所指的对象是id,现在要拷贝对象,克隆方法
class Person implements Cloneable{
    //基本类型
    public int id =1234;
    //引用类型
    public Money M = new Money();
    @Override
    public String toString(){
        return "id:"+id;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException{
        //浅拷贝
        // return super.clone();
        //深拷贝
         Person tmp=(Person)super.clone();
         tmp.M=(Money)this.M.clone();
         return tmp;
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person person1=new Person();
        //*拷贝对象前提
        //1.这个对象可以被克隆
        //2.自定义类型被克隆需要实现Cloneable接口
        //没有new对象,是克隆出来的,会产生一个所指对象的副本(地址不同)
        Person person2=(Person)person1.clone();
        System.out.println(person1.M.money);//19.9
        System.out.println(person2.M.money);//19.9
        System.out.println("=====");
        person2.M.money=99.9;
        System.out.println(person1.M.money);//浅:99.9 深:19.9
        System.out.println(person2.M.money);//99.9
    }
}

[外链图片转存中…(img-CMaxeYOY-1654932797589)]

实现深拷贝 是从代码层次上进行的,不是说某个方法是深拷贝,而是从代码的实现上来看的

this.name.equals(Student.name);
保姆级0基础学java之期末复习!_第39张图片
保姆级0基础学java之期末复习!_第40张图片

你可能感兴趣的:(java,java,开发语言)