Java基础(二)——IDEA快捷键、类和对象、三大特征、构造方法、对象比较、抽象类、接口、模拟发红包

650 阅读24分钟

IDEA常用快捷键

快捷键功能
Alt+回车导入包,自动修正
Ctrl+N查找类
Ctrl+Shift+N查找文件
Ctrl+Alt+L格式化代码
Ctrl+Alt+O优化导入的类和包
Alt+Insert生成代码(如get,set方法,构造函数等)
Ctrl+E或者Alt+Shift+C最近更改的代码
Ctrl+R替换文本
Ctrl+F查找文本
Ctrl+Shift+Space自动补全代码
Ctrl+空格代码提示
Ctrl+Alt+Space类名或接口名提示
Ctrl+P方法参数提示
Ctrl+Shift+Alt+N查找类中的方法或变量
Alt+Shift+C对比最近修改的代码
Shift+F6重构-重命名
Ctrl+Shift先上键
Ctrl+X删除行
Ctrl+D复制行
Ctrl+/ 或 Ctrl+Shift+/注释(// 或者// )
Ctrl+J自动代码
Ctrl+E最近打开的文件
Ctrl+H显示类结构图
Ctrl+Q显示注释文档
Alt+F1查找代码所在位置
Alt+1快速打开或隐藏工程面板
Ctrl+Alt+ left/right返回至上次浏览的位置
Alt+ left/right切换代码视图
Alt+ Up/Down在方法间快速移动定位
Ctrl+Shift+Up/Down代码向上/下移动。
F2 或Shift+F2高亮错误或警告快速定位

关闭当前项目

在这里插入图片描述

方法定义时注意事项:

1.方法应当定义在类当中,但是不能在方法中再定义方法,不能嵌套
2.方法定义的前后顺序无所谓
3.方法定义之后不会执行,如果希望执行,一定要调用:单独调用、打印调用、赋值调用
4.如果方法有返回值,那么必须写上“return 返回值”
5.return之后的返回值数据,必须和方法的返回值类型对应起来
6.对于一个void没有返回值的方法,不能写return后面的返回值,只能写return自己
7.对于void方法当中最后一行的return可以省略不写。
8.一个方法当中可以有多个return,但是要保证同时只有一个会被执行到,两个return不能连写。

方法的重载Overload

对于功能相似的方法,因为参数列表不同,写不同的方法名太过麻烦了,所以引入方法重载的概念。

多个方法的名称相同,但是参数列表不同。

方法重载与下列因素有关:
1.方法的参数个数不同
2.方法的参数类型不同
3.方法的参数多类型顺序不同

方法重载与下列因素无关:
1.与参数的名称无关
2.与方法的返回值类型无关

Java 的数组

数组的特点:
1.数组是一种引用数据类型
2.数组当中的多个数据,类型必须统一,跟JavaScript不同,JavaScript数组中数据的类型可以不同。
3.数组的长度在程序运行期间不可改变

数组的初始化,在内存当中创建一个数组,并且向其中赋予一些默认值

两种常见的初始化数组方式:
1.动态初始化(指定长度)
2.静态初始化(指定内容)

动态初始化数组格式:

数据类型【】 数组名称 = new 数据类型/数组长度

int[] arr1 = new int[300];
String[] arr2 = new String[5];
静态初始化数组格式:

数据类型【】 数组名称 = new 数据类型【】{元素1、元素2…}

int[] arr = new int[] {5,15,25};
String[] arr2 = new String[] {"hello","world","java"};
使用静态初始化时格式还可以省略一下

省略格式:数据类型【】 数组名称 = {元素1、元素2…}

注意事项:
1.静态初始化没有直接指定长度,但是仍然会自动推算得出长度
2.静态初始化标准格式可以拆分成为两个步骤

int[] arr1 = {10,20,30};
int[] arr2;
arr2 = new int[] {10,20,30};
使用初始化建议

如果不确定数组当中的具体内容,用动态初始化;否则,已经确定了具体的内容,用静态初始化。

访问数组元素的格式:

数组名称[索引值]

Java的内存需要划分为5个部分

1.栈(stack):存放的都是方法的局部变量。方法的运行一定要在栈当中运行。
局部变量:方法的参数,或者是方法()内部的变量
作用域:一旦超出作用域,立刻从栈内存当中消失
2.堆(heap):凡是new出来的东西,都在堆当中。堆内存里面的东西都有一个地址值:16进制。
堆内存里面的数据都有默认值。规则:
如果是整数 默认为0
如果是浮点数 默认为0.0
如果是字符 默认为’\u0000’
如果是布尔 默认为false
如果是引用类型 默认为null
3.方法区(Method Area):存储.class相关信息,包含方法的信息。
4.本地方法栈(Native Method Stack):与操作系统相关。
5.寄存器(pc Register):与CPU相关。


面向对象和面向过程

面向过程

当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节。

面向对象

当需要实现一个功能的时候,不关心具体的步骤,而是找一个已经具有该功能的人,来帮我做事儿。

类和对象

类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。

现实中,描述一类事物:

  • 属性:就是该事物的状态信息
  • 行为:就是该事物能够做什么

举例:小猫

  • 属性:名字,体重,年龄,颜色
  • 行为:走,跑,叫

定义一个标准类

一个标准的类通常要拥有以下四个组成部分:
1.所有成员变量都要使用private关键字修饰
2.为每一个成员变量编写一对getter/setter方法
3.编写一个无参数的构造方法
4.编写一个全参数的构造方法

这样标准的类也叫做Java Bean

例子:
在这里插入图片描述
编写时写完变量可以直接生成getter和setter代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public class Student {
    private String name; //姓名
    private int age;  //年龄

    //无参数构造方法
    public Student() {
    }
    //全参数构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public class DemoStudent {
    public static void main(String[] args) {
        Student stu1 = new Student();
        stu1.setName("克苏鲁的呼唤");
        stu1.setAge(20);
        System.out.println("name: " + stu1.getName() + ",age:" + stu1.getAge());
        System.out.println("=======================");

        Student stu2 = new Student( "恩齐都", 21);
        System.out.println("name: " + stu2.getName() + ",age:" + stu2.getAge());
    }
}

效果:
在这里插入图片描述

对象

对象:是一类事物的具体体现。对象是类的一个实例,必须局部该类事物的属性和行为

类和对象的关系

  • 类是对一类事物的描述,是抽象的
  • 对象是一类事物的实例,是具体的
  • 类是对象的模板,对象是类的实体
    在这里插入图片描述
    通常情况下,一个类并不能直接使用,需要根据类创建一个对象,才能使用。
    1.导包,也就是指出需要使用的类在什么位置。
    import 包名称.类名称
import cn.itcast.day1.demo1.Student

对于和当前类属于同一个包的情况,可以省略包语句不写

2.创建,格式:
类名称 对象名 = new 类名称();

Student stu = new Student();

3.使用分两种情况
使用成员变量:对象名.成员变量名
使用成员方法:对象名.成员方法名(参数)


局部变量和成员变量不同

1.定义的位置不一样【重点】
局部变量:在方法的内部
成员变量:在方法的外部,直接写在类当中

2.作用范围不一样【重点】
局部变量:只有方法当中才可以使用,出了方法就不能使用了
成员变量:整个类全都可以通用

3.默认值不一样【重点】
局部变量:没有默认值,如果想要使用,必须手动进行赋值
成员变量:如果没有赋值,会有默认值,规则和数组一样

4.内存的位置不一样
局部变量:位于栈内存
成员变量:位于堆内存

5.生命周期不一样
局部变量:随着方法进栈而诞生,随着方法出栈而消失,存在时间要短一些。
成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失。

当方法的局部变量和类的成员变量重名的时候,根据”就近原则“,优先使用局部变量。
如果需要访问本类当中的成员本来,需要使用格式:this.成员变量名

public class Testday1 {
    //成员变量
    String num = "123"; 

    public void call(){
        //局部变量
        int n = 10;
         System.out.println(n);
    }

    public static void main(String[] args) {
        System.out.println(num);
        call();
    }
}

面向对象三大特征:封装、继承、多态

封装

1.方法就是一种封装
2.关键字private也是一种封装,一旦使用了private进行修饰,那么本类种仍然可以随意访问。但是超出了本类范围就不能再直接访问了。但可以间接访问。间接访问private成员变量,就是定义一对getter/setter方法,类似于JavaScript中的闭包。
对于getter来说,不能有参数,返回值类型和成员变量对应
对于setter来说,不能有返回值。参数类型和成员变量对应

public class Testday1 {
    //成员变量
    String name; //姓名
    private int age; //年龄

    public void show(){
        System.out.println("My name is " + name + "and age is " + age);
    }
    //设置一个成员方法,专门用于向age设置数据
    public void setAge(int num) {
        age = num;
    }
    //这个成员方法专门用于获取age的数据
    public int getAge() {
        return age;
    }
}

封装就是将一些细节信息隐藏起来,对于外界不可见

继承

继承是多态的前提,没有继承就没有多态
继承主要解决的问题就是:共性抽取

父类:也可以叫做基类
子类:也可以叫做派生类

在继承的关系中,子类就是一个父类,子类可以被当作父类来看待

定义父类的格式:(一个普通的类定义)
定义子类的格式:

public class 子类名称 extends 父类名称 {

}
//定义一个员工的子类,讲师
public class extendsDemo extends Employee{
     
}
//定义一个父类 员工
class Employee {
    public void method(){
        System.out.println("方法执行!");
    }
}

在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式:

  1. 直接通过子类对象访问成员变量
  2. 间接通过成员方法访问成员变量,该方法属于谁,就优先用谁,没有则向上找。

访问成员变量:

  1. 局部变量: 直接写成员变量名
  2. 本类的成员本类名: this.成员变量名
  3. 父类的成员变量: super.成员变量名

继承关系中,父子类构造方法的访问特点:

  • 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。
  • 可以通过super关键字来子类构造调用父类重载构造
  • super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。
public class extendsDemo extends Employee{
    @Override  //如果@Override没有报错,则证明重写正确
    public void  method(){
        int a = super.a;
    }
    public extendsDemo(){
        //super();  //在调用父类无参构造方法
        super(20);
        System.out.println("子类构造方法");
    }
}
//定义一个父类 
class Employee {
    int a;
    public void method(){
        System.out.println("方法执行!");
    }
    public Employee(){
        System.out.println("父类无参构造方法!");
    }
    public Employee(int num) {
        System.out.println("父类有参构造方法!");
    }
}

super关键字的用法有三种:

  • 在子类的成员方法中,访问父类的成员变量
  • 在子类的成员方法中,访问父类的成员方法
  • 在本类的构造方法中,访问本类的另一个构造方法
class Zi extends Employee {
    public Zi(){
        this(123); //本类的无参构造调用本类的有参构造
    }
    public Zi(int n){

    }
    public Zi(int a,int b){

    }
}

super和this的应用

public class FuZiDemo {
    public static void main(String[] args) {
        Zidemo zi = new Zidemo();
        zi.method();
        zi.show();
    }
}

class Fu {
    int num = 10;
    public void method(){
        System.out.println("父类方法");
    }
}

class Zidemo extends Fu {
    int num = 20;
    @Override
    public void method(){
        System.out.println("子类方法");
    }
    public void show(){
        int num = 30;
        System.out.println(num);  //30
        System.out.println(this.num); //20
        System.out.println(super.num);
    }
}

在这里插入图片描述
在这里插入图片描述

Java语言中的继承三个特点

在这里插入图片描述

方法的重写(Override)

概念:在继承关系中,方法的名称一样,参数列表也一样
可以使用@Override检查是否正确重写。

public class extendsDemo extends Employee{
    @Override  //如果@Override没有报错,则证明重写正确
    public void  method(){
        
    }
}
//定义一个父类 员工
class Employee {
    public void method(){
        System.out.println("方法执行!");
    }
}

注意事项:

  • 必须保证父类子类之间的名称相同,参数列表也相同。
  • 子类方法的返回值必须小于等于父类方法的返回值范围
  • 子类方法的权限必须大于等于父类方法的权限修饰符
    public > protected > (default) > private
    备注:(default)不是关键字default,而是什么都不写,留空

设计原则

对于已经投入使用的类,尽量不要进行修改,推荐定义一个新的类,来重复利用其中共性内容,并且添加改动新内容。
在这里插入图片描述

发红包练习

在这里插入图片描述

import java.util.ArrayList;
import java.util.Random;

public class SendHongbao {
    public static void main(String[] args) {
        //群主
        Manager manager = new Manager("群主",100);
        //三个群成员
        Member one = new Member("成员1",0);
        Member two = new Member("成员1",0);
        Member three = new Member("成员1",0);

        manager.show();
        one.show();
        two.show();
        three.show();
        System.out.println("***********************");
        //群主发80圆,分三个红包
        ArrayList<Integer> redList = manager.send(80,3);
        //三个成员收红包
        one.receive(redList);
        two.receive(redList);
        three.receive(redList);

        manager.show();  //100 - 80 = 20
        one.show();
        two.show();
        three.show();
    }
}

class User{
    private String name;  //姓名
    private int money;  //余额,当前用户拥有的钱数

    public User(){

    }
    public User(String name, int money) {
        this.name = name;
        this.money = money;
    }
    //展示一下当前用户有多少钱
    public void show(){
        System.out.println("我叫:" + name + ",我有:¥" + money);
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getMoney() {
        return money;
    }

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

class Manager extends User{
    public Manager(){

    }
    public Manager(String name, int money) {
        super(name, money);
    }
    //发红包方法
    public ArrayList<Integer> send(int totalMoney,int count){
        //首先需要一个集合,用来存储若干个红包的金额
        ArrayList<Integer> redList = new ArrayList<>();
        //看一下群主自己有多少钱
        int ownMoney = super.getMoney();  //群主当前余额
        if(totalMoney > ownMoney){
            System.out.println("余额不足");
            return redList;  //返回空集合
        }
        //扣钱,重新设置余额
        super.setMoney(ownMoney - totalMoney);
        //发红包需要平均拆分为count份
        int avg = totalMoney / count;
        int mod = totalMoney % count; //剩下来的零头
        //除不开的零头,放在最后一个红包中,把红包全部放到一个集合中
        for (int i = 0; i < count - 1; i++) {
            redList.add(avg);
        }
        //最后一个红包
        int last = avg + mod;
        redList.add(last);

        return redList;
    }
}

class Member extends User{
    public Member() {
    }

    public Member(String name, int money) {
        super(name, money);
    }
    public void receive(ArrayList<Integer> list){
        //从多个红包当中随便抽取一个给自己,随机获取一个集合中的索引编号
        int index = new Random().nextInt(list.size());
        //根据索引,从集合中删除,并且得到被删除的红包给自己
        int data = list.remove(index);

        //当前成员本来有多少钱
        int money = super.getMoney();
        //重新设置成员的钱
        super.setMoney(money + data);
    }
}

运行结果:
在这里插入图片描述

多态

访问成员变量的两种方式:

  1. 直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找
  2. 间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找

在多态的代码当中,成员方法的访问规则是:

  • 看new的是谁,就优先用谁,没有则向上找
Fu obj = new Zi();  //多态

在这里插入图片描述

对象的向上转型

格式
父类名称 对象名 = new 子类名称();Animal animal = new Cat();
含义:右侧创建一个子类对象,把它当作父类来看待创建了一只猫,当作动物看待,没问题

注意事项:向上转型一定是安全的。从小范围转向了大范围,从小范围的猫,向上转换成为了更大范围的动物

对象的向下转型

其实就是一个【还原】的动作

格式
子类名称 对象名 = (子类名称)父类对象Cat cat = (Cat)animal;
含义:将父类对象,【还原成为本来的子类对象】本来是猫,已经被当作动物了,还原回来成为本来的猫

注意事项:

  • 必须保证对象本来创建的时候就是猫,才能向下转型为猫
  • 如果对象创建的时候本来不是猫,现在非要向下转型成为猫,就会报错。

例子:

public class DuoTaiDemo {
    public static void main(String[] args) {
        //对象的向上转型,父类引用指向子类对象
        AnimalClass animal = new CatClass();
        animal.eat();  //猫吃鱼
        /*对象一旦向上转型为父类,那么就无法调用子类原本特有的方法
        animal.catchMouse(); //错误写法
        解决方案:用对象的向下转型[还原]
        * */

        //向下转型,进行还原动作
        CatClass cat = (CatClass) animal;
        cat.catchMouse();
    }
}

abstract class AnimalClass {
    public abstract void eat();
}

class CatClass extends AnimalClass {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
    //子类特有方法
    public void catchMouse(){
        System.out.println("猫抓老鼠了!");
    }
}

在这里插入图片描述

USB接口案例

笔记本电脑在这里插入图片描述
案例分析在这里插入图片描述

在这里插入图片描述
USB接口

public interface USBInterface {

    public abstract void open();  //打开设备
    public abstract void close();  //关闭设备
}

public class UsbDemo {
    public static void main(String[] args) {
        //首先创建一个笔记本电脑
        Computer computer = new Computer();
        computer.powerOn();
        //准备一个鼠标
//        Mouse mouse = new Mouse();
        //首先进行向上转型
        USBInterface usbMouse = new Mouse();
        //参数是USB类型
        computer.useDevice(usbMouse);

        //创建一个USB键盘
        Keyboard keyboard = new Keyboard();  //没有使用多态写法
        computer.useDevice(keyboard);

        computer.powerOff();
    }
}
//鼠标就是一个USB设备
class Mouse implements USBInterface {
    @Override
    public void open() {
        System.out.println("打开鼠标");
    }
    @Override
    public void close() {
        System.out.println("关闭鼠标");
    }
}
//键盘是一个USB设备
class Keyboard implements USBInterface {
    @Override
    public void open() {
        System.out.println("打开键盘");
    }
    @Override
    public void close() {
        System.out.println("关闭键盘");
    }
}

class Computer{
    public void powerOn() {
        System.out.println("笔记本电脑开机");
    }

    public void powerOff() {
        System.out.println("笔记本电脑关机");
    }
    //使用USB设备的方法,使用接口作为方法的参数
    public void useDevice(USBInterface usb){
        usb.open(); //打开设备

        usb.close();//关闭设备
    }
}
运行结果:

在这里插入图片描述

构造方法

构造方法是专门用来创建对象的方法,当我们通过关键字new来创建对象时,其实就是在调用构造方法。
格式:

public 类名称(参数类型 参数名称){
	方法体
}

注意事项:

  • 构造方法的名称必须和所在类名称完全一样,就连大小写也要一样
  • 构造方法不用写返回值类型,连void都不写
  • 构造方法不能return一个具体的返回值
  • 如果没有编写任何构造方法,那么编译器会默认赠送一个构造方法,没有参数、方法体什么都不做
  • 一旦编写了一个构造方法,那么编译器不再赠送了。
public class Testday1 {
	//名称Testday1 相同
    public Testday1(){
        System.out.println("构造方法执行了");
    }
}

Scanner类

Scanner类的功能:可以实现键盘输入数据到程序当中

引用类型一般使用步骤:
1.导包
import 包路径.类名称
只有java.lang包下的内容不需要导包,其他包都需要import语句
2.创建
类名称 对象名 = new 类名称();
3.使用
对象名.成员方法名()

例子:

import java.util.Scanner;
public class ScannerDemo {
    public static void main(String[] args) {
        //System.in代表从键盘输入
        Scanner scanner = new Scanner(System.in);
        //获取键盘输入的int数字
        int num = scanner.nextInt();
        System.out.println("输入的数字是:"+num);
        //获取键盘输入字符串
        String str = scanner.next();
        System.out.println("输入的字符串是:"+str);
    }
}

在这里插入图片描述

Random类

Random类用来生成随机数字

  • 获取一个随机的int数字(范围是int所有范围,有正负两种):int num = r.nextInt()
  • 获取一个随机的int数字(参数代表了范围,左闭右开取键):int num = r.nextInt(3)
    实际上代表的含义是:[0,3) 也就是0~2

ArrayList类

数组的长度不可以改变,但是ArrayList集合的长度可以随意改变。
对于ArrayList来说,有一个尖括号代表泛型。
泛型:也就是装在集合当中所有的元素,全部是统一类型的。
注意:

  • 泛型只能是引用类型,不能是基本类型。
  • 对于ArrayList集合来说,直接打印得到的不是地址值,而是内容。如果内容是空,得到的是空的忠括号:[]

例子:

import java.util.ArrayList;

public class ArrayListdemo {

    public static void main(String[] args) {
        //创建了一个ArrayList集合,集合里面装的全部是string字符串类型的数据
        //备注:从JDK1.7开始,右侧的括号内部可以不写内容,但<>本身还是要写的
        ArrayList<String> list = new ArrayList<>();
        System.out.println(list);  //[]

        //向集合当中添加一些数据,需要用到add方法
        list.add("天气真好");
        list.add("雷雨天");
        System.out.println(list);
    }
}

在这里插入图片描述
如果希望向集合ArrayList忠存储基本数据类型,必须使用基本类型对应的“包装类”。

基本类型包装类(引用类型,包装类都位于java.lang包下)
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

对象之间比较

==是进行对象的地址值比较,如果确实需要字符串的内容比较,可以使用两个方法。

public boolean equals(Object obj):参数可以是任何对象,只有参数是一个字符串并且内容相同的才会给true;否则返回false。
备注:任何对象都能用Object进行接收

public class EqualDemo {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "hello";
        char[] charArray = {'h','e','l','l','o'};
        String str3 = new String(charArray);

        System.out.println(str1==str2);  //true
        System.out.println(str1==str3);  //false
        System.out.println(str2==str3);  //false

        System.out.println(str1.equals(str2));  //true
        System.out.println(str1.equals(str3));  //true
        System.out.println(str2.equals(str3));  //true
    }
}

在这里插入图片描述

静态static关键字

如果一个成员变量使用了static关键字,那么这个变量不再属于对象自己,而是属于所在的类。多个对象共享同一份数据。

public class StaticDemo {
    public static void main(String[] args) {
        Student one = new Student("张三",18);
        one.room = "101教室";  //one的教室和two的教室因为static关键字所以共通
        Student two = new Student("李四",20);

        System.out.println("姓名:" + one.getName() + ",年龄:" + one.getAge() + ",教室:" + one.room);
        System.out.println("姓名:" + two.getName() + ",年龄:" + two.getAge() + ",教室:" + two.room);
    }
}

class Student {
    private String name;  //姓名
    private int age;  //年龄
    static String room; //所在教室

    public Student(){

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

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }
}

在这里插入图片描述
一旦使用使用static修饰成员方法,那么这就成为了静态方法。
静态方法不属于对象,而是属于类的。

如果没有static关键字,那么必须先创建对象,然后通过对象使用成员方法。
对于静态方法来说,可以通过对象名进行调用,也可以直接通过类名来调用。 对于本类当中的静态方法,可以省略类名称。

注意事项:

  • 静态方法只能直接访问静态变量,成员方法可以直接访问成员变量和静态变量
    原因:因为在内存中现有静态内容,后有非静态内容
  • 静态方法当中不能使用this
    原因:this代表当前对象,通过谁调用的方法,谁就是当前对象
  • 根据类名称访问静态成员变量的时候,就和对象没有关系了,只和类有关系。

静态代码块

格式:

public class 类名称{
    static {
        //静态代码块内容
    }
}

特点:当第一次用到本类时,静态代码块执行唯一的一次。
静态的内容总是优先于非静态,所以静态代码块比构造方法先执行。

静态代码块典型用途:用来一次性地对静态成员变量进行赋值。

Arrays类

java.util.Arrays是一个与数组相关的工具类,里面提供了大量的静态方法,用来实现数组常见的操作。
public static String toString(数组):将参数数组变成字符串(按照默认格式:【元素1,元素2…】)

public class ArraysDemo {
    public static void main(String[] args) {
        int[] intArray = {10,20,30};
        //将int数组按照默认格式变成字符串
        String intStr = Arrays.toString(intArray);
        System.out.println(intStr);
        System.out.println(intStr instanceof String);
    }
}

在这里插入图片描述

抽象abstract

抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。

//抽象类:抽象方法所在的类必须是抽象类才行。在class前写上abstract即可
abstract class Animal{
    //这是一个抽象方法,代表吃东西,但是具体吃什么不确定
    public abstract void eat();
}

如何使用抽象类和抽象方法

  1. 不能直接创建new抽象类对象
  2. 必须使用一个子类来继承抽象父类
  3. 子类必须覆盖重写抽象父类当中的所有抽象方法
    覆盖重写:子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
  4. 创建子类对象进行使用
public class Animalabstract {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat();
    }

}
//抽象类:抽象方法所在的类必须是抽象类才行。在class前写上abstract即可
abstract class Animal{
    //这是一个抽象方法,代表吃东西,但是具体吃什么不确定
    public abstract void eat();
}

class Cat extends Animal{
    @Override
    public void eat(){
        System.out.println("猫吃鱼");
    }
}

在这里插入图片描述

接口

接口就是一种公共的规范标准。只要符合规范标准,就可以大家通用。
接口是一种引用数据类型,最重要的就是抽象方法。

如何定义一个接口的格式:

public interface 接口名称 {
	//	接口内容
}

接口当中可以包含的内容:

  1. 常量
  2. 抽象方法
  3. 默认方法
  4. 静态方法
  5. 私有方法

在这里插入图片描述

/*在任何版本的Java中,接口都能定义抽象方法
格式:
public abstrace 返回值类型 方法名称(参数列表)
注意事项:
1.接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
2.这两个关键字修饰符,可以选择性的省略
3.方法的三要素可以随意定义 
* */
public interface MyInterface {
    //抽象方法
    public abstract void method1();
}

接口使用步骤

  1. 接口不能直接使用,必须有一个“实现类”来实现接口
    格式:
public class 实现类名称 implements 接口名称{ ... }
  1. 接口的实现类必须覆盖重写接口中的所有抽象方法
    实现:去掉abstract关键字,加上方法体大括号
  2. 创建实现类的对象,进行使用

例子:

public class InterfaceDemo {
    public static void main(String[] args) {
        /*错误写法,不能直接new接口对象使用
           MyInterface inter = new MyInterface();
        * */
        //创建实现类的对象使用
        MyInterfaceImpl impl = new MyInterfaceImpl();
        impl.method1();
        impl.method2();
    }
}

//使用alt + enter能够快捷产生覆盖MyInterface接口的重写方法
class MyInterfaceImpl implements MyInterface {
    @Override
    public void method1() {
        System.out.println("方法1");
    }
    @Override
    public void method2() {
        System.out.println("方法2");
    }
}

接口

public interface MyInterface {
    //抽象方法
    public abstract void method1();
    public void method2();
}

运行结果:
在这里插入图片描述

接口中定义默认方法

格式:

public default 返回值类型 方法名称(参数列表){
	方法体
}

备注:接口当中的默认方法能够解决接口升级的问题。

public interface MyInterface {
    //抽象方法
    public abstract void method1();
    public void method2();
    //新添加方法改为默认方法,不需要实现类重写
    public default void methods3(){
        System.out.println("新添加的默认方法");
    }
}
public class InterfaceDemo {
    public static void main(String[] args) {
        /*错误写法,不能直接new接口对象使用
           MyInterface inter = new MyInterface();
        * */
        //创建实现类的对象使用
        MyInterfaceImpl impl = new MyInterfaceImpl();
        impl.method1();
        impl.method2();
        //调用默认方法,如果实现类中没有,会向上找接口
        impl.methods3();
    }
}

在这里插入图片描述

接口中的私有方法

我们需要抽取一个公共方法,用来解决两个默认方法之间的重复代码问题。但是这个方法不应该让实现类使用,应该是私有化的。

私有方法只有接口自己能够调用。

  1. 普通私有方法,解决多个默认方法之间重复代码问题
    格式:
private 返回值类型 方法名称(参数列表) {
}
  1. 静态私有方法,解决多个静态方法之间重复代码问题
    格式:
private static 返回值类型 方法名称(参数列表) {
}

例子:

public interface MyInterface {
    //新添加方法改为默认方法,不需要实现类重写
    public default void methods3(){
        System.out.println("新添加的默认方法3");
        say();
    }
    public default void methods4(){
        System.out.println("新添加的默认方法4");
        say();
    }
    //私有方法
    private void say(){
        System.out.println("aaa");
        System.out.println("bbb");
        System.out.println("ccc");
    }
}

接口中的常量

接口当中也可以定义成员变量,但是必须使用public static final三个关键字进行修饰。
从效果上看,这就是接口的【常量】
格式:

public static final 数据类型 常量名称 = "数据值";

一旦使用final关键字,就代表不可改变
接口当中的常量一定要进行明确的赋值

使用接口注意事项

  1. 接口是没有静态代码块或者构造方法的
  2. 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
    格式:
class MyInterfaceImpl implements MyInterface,MyInterface2,MyInterface3
{
}
  1. 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
  2. 如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
  3. 如果实现类锁实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖。
  4. 一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。





一起学习,一起进步 -.- ,如有错误,可以发评论