华清远见重庆中心-面向对象技术总结/个人总结

本文介绍了Java中的标识符命名规则,包括帕斯卡命名法和驼峰命名法。详细讲解了类、方法、变量的命名要求,并探讨了方法的调用,包括通过类名、对象及直接调用。文章还涵盖了面向过程和面向对象编程的概念,强调了面向对象的封装、继承、多态三大特性,并深入讨论了构造方法、成员变量、局部变量和静态成员。此外,还涉及了对象造型/转型、重写equals方法以及多态的应用。
摘要由CSDN通过智能技术生成

Java中标识符的命名规则

标识符

类名、方法名、变量名统称为标识符

标识符命名规范

帕斯卡命名法

所有单词首字母大写

如Employee、ClassName、StudentInfomation

驼峰命名法

第一个单词首字母小写,其余单词首字母大写

如studentInfomation、employee、className

注意:

类名使用帕斯卡命名法

方法名、变量名使用驼峰命名法

变量命名的要求

  • 使用字母、数字、下划线或$符号组成

  • 不能使用数字开头

  • 不能使用关键字

  • 见名知意

方法

解释

方法是定义在类中的一段独立代码,能完成某个事情

定义方法时,提供方法的名称返回值类型参数列表,以上三点称为方法的三要素,定义的方法都需要这三部分

当再使用该方法中的代码时,只需要通过该方法名调用即可

方法可以减少代码冗余

调用方法

  1. 通过类名调用

Math类

Math类是Java中的工具类,用于数学计算

该类中的方法和属性都使用static修饰的,可以直接通过类名调用

在任何类中,通过快捷键alt+7,展示方法列表

//常用方法和属性
System.out.println(Math.PI);//圆周率
System.out.println(Math.E);//自然常数
System.out.println(Math.abs(-5));//绝对值
System.out.println(Math.max(1,2));//最大值
System.out.println(Math.min(2.5,3.2));//最小值
System.out.println(Math.ceil(2.1));//3 向上取整
System.out.println(Math.floor(3.9));//3 向下取整
System.out.println(Math.round(-1.5));//-1 四舍五入
System.out.println(Math.random());//[0,1)直接的随机数
System.out.println(Math.sqrt(9));//3 平方根
System.out.println(Math.cbrt(27));//3 开立方
System.out.println(Math.pow(2,3));//8 2的3次幂

2.通过对象调用

创建对象 语法: 类名 对象名=new 类名([参数])

Scannersc=newScanner(System.in);
sc.方法名();

Randomrd=newRandom();
rd.方法名();

3.在同一个类中,方法A直接调用方法B

class Test{
  void funA(){
    funB();
  }

  void funB(){
    System.out.println("我是B方法");
  }
}

方法调用总结

调用方式

  1. 通过类名调用

  1. 通过对象调用

  1. 直接调用

参数

  • 无参数

Scanner sc=new Scanner(System.in);
sc.next();//调用无参数方法
  • 有参数

Random rd=new Random();
rd.nextInt(10);//调用有参数方法

返回值

  • 没有返回值 方法名的前面用void表示

class Test{
    void funB(){
        System.out.println("我是B方法");
    }
    
    public static void main(String[] args){
        Test t=new Test();
    }
}
  • 有返回值

Random rd=new Random();
int num=rd.nextInt(10);

自定义方法

方法的三要素:

  • 方法名

使用驼峰命名法

  • 方法返回值类型

如果有返回值,使用Java中的任意数据类型,方法体中使用return关键字返回对应类型的数据

如果没有返回值,使用void关键字

  • 方法参数列表

参数写法: 数据类型 形参名.数据类型 形参名

[修饰符] 返回值类型 方法名(参数列表){
    方法体;
}

方法的类型

  • 无参数无返回值

void 方法名(){
    //方法体
    return;//遇到return立即结束方法
}
  • 无参数有返回值

int 方法名(){
    //方法体
    return;
}
  • 有参数无返回值

void 方法名(数据类型1 形参名1,数据类型2 形参名2){
    //方法体
    return;
}
  • 有参数有返回值

//生成a,b中包含最小值,不包含最大值范围内的随机数
double rand(int a,int b){
    double num=Math.floor(Math.random()*Math.abs(a-b)+Math.min(a,b))
    return num;
}

注意

  1. 有返回值的方法,必须要在方法体中加入return并能够执行,同时要return一个该方法返回值类型对应的数据

  1. 没有返回值的方法,可以不用加入return关键字,如果加入return关键字,不能跟上数据

  1. 方法中出现return,会立即结束方法,所以return语句之后不能再有代码

  1. 定义方法时的参数称为形式参数,简称为形参。调用方法时,实际传递的参数称为实际参数,简称实参,实参只需保证数据类型和形参相同即可

编程思想

面向过程编程

Procedure Oriented Programming 简称为POP

是一种基本的编程思想,将一件事情按流程步骤执行,逻辑清晰

每一步都是基于上一步的流程去继续实现

注重于分析问题的步骤

如果逻辑复杂,如xxx管理系统,使用POP就会变得很麻烦

C语言就是一门面向过程的编程语言

面向对象编程

Object Oriented Programming 简称OOP

是一种编程思想,核心是创建解决问题的对象,赋予对象行为和特征,让这些对象互相配合执行

每个对象的行为实际也是面向过程的

注重于全局如何创建完成某件事情的对象,如何适时的调用

这种思想致力于将计算机中的世界,描述的和现实中一致的思想

如洗衣服

pop:得到衣服--->得到洗衣服--->洗--->晾晒

oop:得到衣服对象--->得到洗衣机对象--->调用洗衣机对象的洗衣服行为

总结:

  1. 面向过程:亲历亲为,侧重于分析完成事情的过程

  1. 面向对象:所有事情交给相应的对象完成,侧重于如何创建解决问题的对象

类和对象

类Class

具有相同属性和行为的对象的集合,相当于模板

  • 属性

描述这个类的特征值, 在程序中,通过定义变量实现

  • 行为

描述这个类的动作,在程序中,通过定义方法实现

创建一个Class文件,就是创建一个类

定义类

[修饰符] class 类名{

//属性(定义变量)

//行为(定义方法)

}

/*
*定义车的模板
*属性:变量
*  品牌
*  颜色
*  座位数
*  排量
*  ....
*
*行为:方法
*  跑
*  说话
*  飞
* ....
*/
public class Car(){
    //定义变量  数据类型 变量名:
    String brand;
    String color;
    int seat;
   
    //定义方法
    void run(){
        System.out.println("车在跑。。")
    }
    void introduce(){
    //在方法中可以直接访问同一个类中的属性
    System.out.println("我是一辆"+brand+"牌的"+color+"色的"+seat+"座车")
    }
}

对象 Object

对象由某个类创建出来的具体实例

创建对象

类名 对象名=new 构造方法([参数])

创建出的对象,通过"."操作符访问类中的非私有属性和方法

public class Test4 {
    public static void main(String[] args) {
        // 创建Car类的对象
        //类名 对象名 = new 类名();
        Car benz = new Car();
        //对象.类中的属性和方法
        benz.seat = 5;
        benz.color="白";
        benz.brand="奔驰";
        benz.introduce();
        benz.run();
    }
}

类和对象的关系

对象是类的具体表现,类是对象的模板

如制作月饼的模具就是一个类,每次用这个模具创建出来的月饼就是一个对象

先定义类,才能通过该类获取对象

作业:模拟电子宠物

public class Pet {
    //定义属性
    String type;
   String nickName;
    String birthday;

    //定义行为
    void eat(String food) {
        System.out.println( nickName+ "开始吃"+food);
    }
    void toy(String toy) {
        System.out.println(nickName + "开心的玩"+toy);
    }
    void sing(){
        System.out.println("我是一只鹦鹉,我叫hah,hhhh~~~~");
    }
}
//宠物机
//属性
//  宠物
//方法
//  主界面

import java.util.Scanner;

public class Pet_machine {
    Scanner sc = new Scanner(System.in);
    void createPet(){
        System.out.println("-------------");
        Pet pet = new Pet();//创建一个宠物对象
        //定义方法中的变量,称为局部变量,必须先赋值再使用
        String type="猫咪";
        System.out.println("请选择宠物类型:");
        System.out.println("1.猫咪");
        System.out.println("2.小狗");
        System.out.println("3.鹦鹉");
        int in=sc.nextInt();
        switch (in){
            case 1:
                break;
            case 2:
                type = "小狗";
                break;
            case 3:
                type = "鹦鹉";
                break;
            default:
                System.out.println("输入有误");
        }
        pet.type=type;
        System.out.println("请输入宠物昵称:");
        pet.nickName=sc.next();
        System.out.println("请输入宠物生日:");
        pet.birthday=sc.next();
        System.out.println("宠物已生成!");

        int input=0;
        while (true){
            System.out.println("请选择功能:1.喂食 2.玩耍 3.唱歌 4.退出");
            input=sc.nextInt();
            switch (input){
                case 1:
                    System.out.println("请输入食物:");
                    String food=sc.next();
                    pet.eat(food);
                    break;
                case 2:
                    System.out.println("请输入玩具:");
                    String toy=sc.next();
                    pet.toy(toy);
                    break;
                case 3:
                    pet.sing();
                    break;
            }
            if(input==4){
                break;
            }

        }

    }
}
public class Test1 {
    public static void main(String[] args) {
        Pet_machine z=new Pet_machine();
        z.createPet();


    }
}

成员变量和局部变量

成员变量

定义在类中的变量,称为成员变量,有默认值

数据类型

默认值

整型

0

浮点型

0.0

布尔型

false

引用类型(类、数组、接口)

null

class Person(){
    String name;//成员变量,String是类类型,属于引用类型,默认为null
    int age;//整型,默认0

    void fun(){
        System.out.println((name));//这里能通过编译,可以使用name,输出null
        System.out.println(list[0]);//这里能通过编译,由于list为null,会报空指针异常
    }
}

局部变量

定义在方法中的变量,称为局部变量,没有默认值,赋值后才能使用

class Test{

   public static void main(String[] args){
       int num;//定义在方法中的变量称为局部变量,赋值后才能使用
       System.out.println(num);//无法通过编译
   }
}

成员变量和局部变量相关面试题

简述成员变量和局部变量的区别以及生命周期

成员变量是定义在类中的变量,有默认值,不赋值也能使用

局部变量是定义在方法中的变量,没有默认值,需要赋值后才能使用

成员变量的生命周期:类创建对象,成员变量就会初始化,类的对象被回收,成员变量就会销毁

局部变量的生命周期:方法调用,对局部变量赋值,局部变量初始化,方法调用结束,局部变量失效

构造方法

概念

构造方法也称为构造函数、构造器、constructor

它是一个特殊的方法。

没有返回值部分,方法名和类名一致,在创建对象时通过new调用,给类的成员变量赋值。

class Person{
    //成员变量
    String name;
    int age;
    //这就是一个无参数的构造方法,用于new Person()
    Person(){
    }
    //这就是一个带参数的构造方法,用于new Person("admin",20)
    Person(String name,int age){
        this.name=name;//将参数的值赋值给成员变量
        this.age=age;
    }
}

特点

  1. 创建对象时必须通过new配合构造方法

  1. 创建对象时必须通过new配合构造方法

  1. 构造方法可以存在多个,但是参数不能相同。这些构造方法之间的关系称为方法重载

  1. 每个类默认有一个隐藏的无参数的构造方法,方法体中隐含了一句super()。用于创建无参数的对象

5.如果自己写了带参数的构造方法,默认无参数的构造方法就会失效。如果想要同时拥有带参数和不带参数的构造方法,就需要再次显式的写出来

6.带参数的构造方法常用于初始化成员变量(给类中的变量赋值)

7.构造方法可以限制创建对象时携带的参数

8.构造方法无法通过"."操作符访问,只能通过new关键字创建对象时调用

IDEA中自动生成构造方法

在类空白处右键generate或快捷键alt+insert

在弹出的窗口中,选择Constructor

选择生成的构造方法的参数,全选ctrl+a

面对对象语言的三大特性--封装

封装

使用private关键字对成员变量进行修饰,再提供一组get和set的方法,用于对该属性读取和赋值

可以防止除自身类之外的地方对private修饰的属性进行访问

这样就能保护关键属性或给属性赋一个合理的值

步骤

1.创建类,编写成员变量,对成员变量使用private修饰

class Person{
    private String name;
    private int age;
}

2.给所有成员变量添加set方法,用于赋值

void setName(String name){
    this.name=name;
}
void setAge(int age){
    this.age=age;
}

3.给所有成员变量添加get方法,用于读取

String getName(){
    return name;
}
int getAge(){
    return age;
}

创建该类对象后,无法直接通过.访问属性,只能通过get/set读取和赋值

public static void main(String[] args){
    Person p = new Person();
    //p.name;//无法通过.访问被private修饰的属性
    p.setName("王海");
    String name = p.getName();
}

IDEA中自动生成getter/setter方法

在类中空白处右键generate或快捷键alt + insert,在弹出的窗口中选择getter and setter

在弹出的窗口中,选择要生成get和set方法的成员变量

IDEA中自动使用变量接收对象

在对象后.var或快捷键ctrl+alt+v

public static void main(String[] args) {
    //创建对象自动使用变量保存 ctrl + alt + v 或 对象.var
    Employee employee = new Employee();
}

Windows中的快捷键

windows + D 进入桌面

windows + E 进入文件资源管理器

Typora中的快捷键

1-6级标题 CTRL + 1~6

加粗 选中文字 CTRL + B

倾斜 选中文字 CTRL + I

倾斜 选中文字 CTRL + U

列表 - 空格 缩进 tab

表格 CTRL + T

整段代码 ```语言

嵌入代码 代码

IDEA中常用快捷键

复制粘贴 CTRL + D

自动接收对象 CTRL + ALT + V

自动生成构造方法等 ALT + Insert

自动调整格式 CTRL + ALT + L

删除整行 CTRL + X

CTRL + Y 可以设置为删除整行或配合撤销(CTRL + Z)恢复

IDEA中常用设置

字体

开启忽略大小写匹配

面向对象综合练习--简易xxx管理

图书类Book

package test4;
/*
图书类
书名
作者
类型
出版社
价格

定义私有属性
自动生成全参构造方法,无参构造方法getter/setter、toString()
 */
public class Book {
    private int id;
    //封装属性
    private String name;
    private String author;
    private String type;
    private String publisher;
    private double price;

    public Book(int id, String name, String author, String type, String publisher, double price) {
        this.id = id;
        this.name = name;
        this.author = author;
        this.type = type;
        this.publisher = publisher;
        this.price = price;
    }

    Book(){

    }

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", type='" + type + '\'' +
                ", publisher='" + publisher + '\'' +
                ", price=" + price +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

管理员类Manager

package test4;

import java.util.Arrays;

/*
图书管理员
属性
 保存图书的容器

方法
  增加图书
  删除图书
  修改图书
  查看图书
 */
public class Manager {
    //保存图书的容器,该睡醒只能当前类使用,使用private修饰,不提供get/set
    private Book[] booklist=new Book[20];

    //添加
    void addBook(Book book){
        for (int i=0;i<booklist.length;i++){
            if (booklist[i]==null){
                booklist[i]=book;
                //停止循环 防止装满
                break;
            }
        }

    }

    //查看所有图书及图书的详细信息
    void showall(){
        for (int i=0;i<booklist.length;i++){
            if (booklist[i]!=null){
                System.out.println(booklist[i]);
            }
        }
    }

    //通过图书编号id删除
    void delete(int id){
        for (int i=0;i<booklist.length;i++){
            Book book=booklist[i];
            if (book!=null && book.getId()==id){
                book = null;
                break;
            }
        }
    }

    //通过id到对应的图书对象
    Book getBookById(int id){
        //遍历当前所有的图书对象
        for (int i=0;i<booklist.length;i++){
            Book book=booklist[i];
            //如果遍历未发现满足条件,返回null
            if (book!=null && book.getId()==id){
                //返回对应的图书
                return book;
            }
        }
        //如果遍历未发现满足条件,返回null
        return null;
    }

    //查看所有图书
    void showallbookname(){
        for (int i=0;i<booklist.length;i++){
            if (booklist[i]!=null) {
//                System.out.println(booklist[i].getName());
                System.out.println();
            }
        }
    }

    //修改图书信息,比如价格
    void update(int id,double newPrice){
        //根据id获取需要修改的图书
        //调用当前类中定义的根据id查询Book对象的方法
        Book book=getBookById(id);
        if (book!=null){
            book.setPrice(newPrice);
        }else {
            System.out.println("该图书不存在");
        }
    }

    public static void main(String[] args) {
        Manager manager = new Manager();

        //通过全参的方法创建对象
        Book book=new Book(10010,"天龙八部","金庸","小说","xxxx",66);
        manager.addBook(book);

        //通过无参构造方法创建对象
        Book book1=new Book();
        //通过set方法赋值
        book1.setId(10011);
        book1.setName("老人与海");
        book1.setAuthor("海明威");
        book1.setType("小说");
        book1.setPublisher("天津人民出版社");
        book1.setPrice(10);
        manager.addBook(book1);

        manager.showall();
    }
}

程序入口类Main

package test4;

import java.util.Random;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        //创建管理员对象
        Manager manager = new Manager();

        while (true){
            System.out.println("请选择功能:1.添加图书\t2.修改图书\t3.删除图书\t4.查看所有图书\t5.查看图书详情\t6.退出");
            int input=sc.nextInt();
            switch (input){
                case 1:
                    Random rd=new Random();
                    int id = new Random().nextInt(9000)+1000;
                    System.out.println("请输入图书名称:");
                    String name=sc.next();
                    System.out.println("请输入图书作者:");
                    String author=sc.next();
                    System.out.println("请输入图书类型:");
                    String type=sc.next();
                    System.out.println("请输入图书出版社:");
                    String publisher=sc.next();
                    System.out.println("请输入图书价格:");
                    int price=sc.nextInt();
                    //创建一个图书对象
                    Book book = new Book(id,name, author,type,publisher,price);
                    manager.addBook(book);
                    break;
                case 2:
                    System.out.println("请输入需要修改的图书编号:");
                    int updateId=sc.nextInt();
                    System.out.println("请输入要修改的价格:");
                    int updatePrice=sc.nextInt();
                    double newPrice=sc.nextDouble();
                    manager.update(updateId,updatePrice);
                    System.out.println("修改成功!");
                    break;
                case 3:
                    System.out.println("请输入需要删除图书的编号:");
                    manager.delete(sc.nextInt());
                    break;
                case 4:
                    manager.showallbookname();
                    break;
                case 5:
                    manager.showall();
                    break;
                case 6:
                    System.exit(0);
                    break;
            }
        }
    }
}

面向对象三大特性--继承

概念

类B使用extends(延伸)关键字"继承"类A。

语法:class 类B extends 类A{}

类B称为类A的子类,衍生类,subClass

类A称为类B的父类,超类、supClass

继承后,子类就能访问父类中的非私有(没有使用private修饰)成员变量和成员方法。

class A{
private String secret="父类中的私有属性";
String name="父类";
void info(){
System.out.println("父类中的非私有方法");
}
}
class B extends A{
void fun(){
System.out.println(secret);//无法访问父类中的私有成员变量
System.out.println(name);//可以访问非私有成员变量
info();//可以直接调用父类中的非私有方法
}
}
  • 将多个类中的公共代码提取出来保存到一个公共类中,这些类使用extends"继承"这一个公共类,从而减少这些类中的冗余代码。

  • 如猫类、狗类都有类型、昵称等属性,也有吃、睡等方法,那就可以定义一个动物类,将这些公共的属性和方法定义在动物类这个父类中,再让猫类和狗类这些子类继承动物类。这样就能直接通过子类访问父类中的内容。

特点

  1. 如果多个类之中有相同的代码,可以将这些代码提取出来到一个公共的类中,这个类就是父类。再让那些类去extends继承这个父类,那些类就是子类。子类就无需再写重复代码

  1. 子类中或子类对象可以直接访问父类中非私有(不用private修饰)属性和方法

  1. 创建子类对象时,会先执行父类中相应的构造方法

  1. 子类继承父类后,通常会对对父类中的方法进行拓展或覆盖,这称为方法重写。重写后,子类再调

用该方法时,执行的是重写后的内容

  1. Java中是单继承。一个子类只能extends一个父类,一个父类可以有很多子类

  1. Java中可以多重继承,类A可以继承类B,类B继承类C,这是类A既是类B的子类,也是类C的子

类,类A可以访问类B和类C中的非私有成员

  1. 任何类都是Object类的子类

方法重写和方法重载

方法重写override

当子类继承父类后,可以对父类中的方法进行扩展或覆盖。这个过程称为方法重写。

方法重写要求

方法名、返回值、参数列表必须和父类一致

访问权限不能比父类更严格(访问修饰符的范围要么一致要么更大)

不能抛出比父类更大的异常

IDEA中如果要重写方法,使用CTRL + O在弹出的窗口中选择要重写的方法

方法重载overload

在一个类中,如果多个方法的方法名相同,参数列表不同时,这些方法称为重载的方法。

同名不同参

重载用于,在一个类中,某个方法在不同的条件下,执行不同的内容。

方法重载要求

方法名相同

参数必须不同(数量、类型)

与返回值无关

重载和重写相关面试题

说出重载与重写的异同

相同点:方法名不变

不同点:

重载在一个类中,重写在继承关系中子类重写父类

重载参数必须不同,重写参数必须相同

重载返回值无要求,重写返回值必须相同

构造方法能重载吗?能重写吗?

构造方法可以重载。构造方法不能重写。

构造方法在执行时,一定会创建对象吗?

不一定。创建子类时会自动执行父类构造方法,但不会创建父类对象。

以下代码执行会输出什么结果

class Father(){
    Father(){
        fun();
    }
    void fun(){
        System.out.println("父类中的普通方法");
    }
}

class Son extends Father{
    Son(){
        fun();
    }
    void fun(){
        System.out.println("子类中的普通方法");
    }
}

class Test{
    public static void main(String[] args){
        //1.创建父类对象,调用父类中无参构造方法
        //2.无参构造方法中调用fun(),调用父类中的方法,输出“父类中的普通方法”
        new Father();//父类中的普通方法
        //1.创建子类对象,先调用父类中无参构造方法
        //2.无参构造方法中调用fun(),由于fun()子类对其进行了重写,调用的是重写后的方法,
        输出"子类中的普通方法"
        //3.执行子类中无参构造方法,调用重写后的fun(),输出“子类中的普通方法”
        new Son();//"子类中的普通方法"打印两次
    }
}
//最终输出
//父类中的普通方法
//子类中的普通方法
//子类中的普通方法

this和super关键字

这两个关键字,都可以当做对象使用,也可当做构造方法使用。

当做对象使用

用法:this.属性或this.方法,super.属性或super.方法

此时的this表示当前类的对象,super表示当前类的父类对象

class Person{
    private String name;
    public void setName(String name){
        //这里的this表示当前类的对象Person对象
        //相当于Person p = new Person();中的p
        this.name=name;
    }
    public String getName(){
        return name;
    }
}

class Man extends Person{
    void fun(){
        //这里的super表示当前类的父类对象
        //Person p = new Person();
        //super表示上句话中的p
        System.out.println(super.getName());
    }
}

当做构造方法使用

用法:this([参数])或super([参数])

此时的this([参数])表示当前类的某个构造方法。如this()表示当前类的无参构造方法。

super([参数])表示当前类的父类的某个方法。如super()表示当前类的父类的无参构造方法。

如果当做构造方法使用时,只能写在另一个构造方法的第一行。

class Person{
    String name;
    int age;

    Person(){
    }

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

class Woman extends Person{
    Woman(){
        super("admin",20);
    }
}

class Main{
    public static void main(String[] args){
        //调用Woman中的无参构造方法
        //super("admin",20),执行父类中的 Person(String name,int age)
        new Woman();
    }
}

注意

如果父类中有无参数的构造方法,在子类的构造方法中,可以不写super(),默认自动调用。

如果父类中有带参数的构造方法,没有无参数的构造方法,在子类的构造方法中,必须要有super([参

数])

  • 父类和子类中都没有构造方法(只有默认的无参构造方法)

class Father{
    //默认会有
    /*
        public Father(){}
    */
}

class Son extends Father{
    //默认会有
    /*
        public Son(){
        super();
        }
    */
}
  • 父类中没有无参构造方法,子类中就必须调用父类中对应的构造方法

class Father{
    String name;
    //由于该构造方法的出现,默认无参数的构造方法就会失效
    Father(String name){
        this.name=name;
    }
}

//这时子类继承会报错
class Son extends Father{
    //因为每个类中都有这段代码
    /*
    Son(){
        //但当前继承的父类中没有无参构造方法
        super();
    }
    */
}

//解决方式1.给父类中添加无参构造方法
class Father{
    String name;
    Father(String name){
        this.name=name;
    }

    Father(){
    }
}

//解决方式2.子类中添加同样的构造方法,目的是为了调用父类中的对应构造方法
class Son extends Father{
    Son(String name){
        super(name);
    }
}

作业:模拟组装手机

摄像头类

package test5;
/*
camera:摄像头
像素:pixel
 */
public class Camera extends Hardware{
    private String pixel;

    public Camera(String name, String pixel) {
        super(name);
        this.pixel = pixel;
    }
}

处理器类

package test5;
/*
processor:处理器
频率
品牌
型号
 */

public class Processor extends Hardware{
    private String frequency;
    private String type;

    public Processor(String name, String frequency, String type) {
        super(name);
        this.frequency = frequency;
        this.type = type;
    }
}

屏幕类

package test5;
/*
screen:屏幕
品牌
分辨率,size
材质,material
 */
public class Screen extends Hardware{
    private String size;
    private String material;

    public Screen(String name, String size, String material) {
        super(name);
        this.size = size;
        this.material = material;
    }

}

硬件类

package test5;
/*
公共属性
品牌
 */
public class Hardware {
    private String name;

    public Hardware(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Hardware{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

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

程序入口Main方法

package test5;

import java.util.Random;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Processor processor1 = new Processor("因特尔/Inter","3.60Ghz","奔腾");
        Processor processor2 = new Processor("酷睿/kr","5Ghz","Inter 酷睿 i5");
        Processor processor3 = new Processor("AMD","5.9G","Ryzen 5");

        Screen screen1 = new Screen("ips屏幕-1080p","1920*1080","液晶面板");
        Screen screen2 = new Screen("led屏幕-p10","80*60","led晶片,反光杯,金属阳极,金属阴极");

        Camera camera1 = new Camera("小米","1.8亿像素");
        Camera camera2 = new Camera("华为","5000万像素");
        Camera camera3 = new Camera("海康威视","400万像素");

        Processor[] processors=new Processor[3];
        processors[0]=processor1;
        processors[1]=processor2;
        processors[2]=processor3;

        Screen[] screens = new Screen[2];
        screens[0] = screen1;
        screens[1] = screen2;

        Camera[] cameras=new Camera[3];
        cameras[0] = camera1;
        cameras[1] = camera2;
        cameras[2] = camera3;

        Random rd=new Random();
        for (int i=0;i<5;i++){
            int index1= rd.nextInt(3);
            int index2= rd.nextInt(2);
            int index3= rd.nextInt(3);

            System.out.println("Processor:"+processors[index1]);
            System.out.println("Screen:"+screens[index2]);
            System.out.println("Camera:"+cameras[index3]);
            System.out.println("----------------------");

        }
    }
}

包package

通过包可以将.java源文件进行结构化管理,相当于windows中的文件夹。

不同的包中,可以保存相同的.java源文件。

某个类在某个包中时,会在该类的代码最上加入 package 包名 ;

包的命名

包名通常使用公司域名的倒序形式。

baidu.com是百度的域名,有一个test的项目,包名写为com.baidu.test

包名中的".",相当于进入文件夹

如com.baidu.test,会创建3个文件夹:com下有baidu,baidu下有test。

导入包

如a包中的类要使用b包中的类时,需要在a包中的类中,导入b包或b包中的某个类。

如在使用Scanner时,就需要导入Scanner所在的java.util包。 import java.util.Scanner;

在IDEA中,如果是通过自动补全的形式写的代码,会自动导入该类,

或设置自动导包删包。

如果需要手动导入包,在报错的位置上按下快捷键alt+回车,

如果多个类,类名相同但在不同的包中,使用该类时选择合适的包。

访问修饰符

访问修饰符可以限制某个类、属性或方法的访问权限

用法:

修饰类:访问修饰符 class 类名{}

修饰属性:访问修饰符 数据类型 变量名;

修饰方法:访问修饰符 返回值类型 方法名(){}

访问修饰符

含义

可以修饰

public

公共的

类、方法、属性

protected

受保护的

方法、属性

不写

默认的

类、方法、属性

private

私有的

方法、属性

访问权限表

同一个类中

同一个包中的不同类

不同包中的子类

不同包中的非子类

public

protected

×

不写

×

×

private

×

×

×

访问权限从大到小

public >>> protected >>> 默认的 >>> private

final关键字

修饰属性

当final修饰属性时,该属性的值不可更改,这个属性称为常量。

常量在程序运行过程中,保存的值不能编号,所以定义常量时需要初始化。

常量名所有字母大写,多个单词之间用_隔开。

final 数据类型 常量名;
final int NUM = 123;
final double PI = 3.14;

修饰方法

当final修饰方法时,该方法不能被重写。

在方法的返回值前加上final。

public class Father{
    public final void fun(){
    }
}

public class Son extends Father{
    //会报错,无法对final方法进行重写
    @Override
    public void fun(){
    }
}

修饰类

当final修饰类时,该类不能被继承。

定义类,在class前加final

public final class Father{
    public final void fun(){
    }
}

//会报错,提示该类无法继承Father
public class Son extends Father{

}

创建对象时的内存变化

Object类

是java中所有类的父类。每个类都是这个类的子类,但没有使用extends体现出来

该类中定义了很多方法,通常需要进行重写。

对象造型/对象转型/cast

类似于原始类型中的数据类型转换。对象A转换为对象B的过程,称为对象转型。

在非继承关系的两个对象中,无法转型。

向下转型

父类对象转换为子类对象的过程,称为向下转型。强制转换

//一个父类对象
Object obj = new Object();
//默认无法直接将obj使用Person对象接收
//"强制转换"
Person p = (Person) obj;

向上转型

子类对象转换为父类对象的过程,称为向上转型。自动转换

//一个子类对象
Person p = new Person();
//默认子类对象可以用父类变量接收 多态
Object obj = p;

重写equals方法

如果两个对象的属性全部相同,在日常的业务逻辑中,可以视为这两个对象是同一个对象。

但是默认使用new创建的对象,就算属性一致,也是不同的内存地址,

如果用==比较,比较的是对象的内存地址,地址不同,返回false。

所以对象比较相同不能使用==

这时就需要自定义一套比较的方

这时就需要自定义一套比较的方法,Object中有一个equals方法,用于比较两个对象是否相同,

但是Object中的equals方法用==比较,所以对该方法进行重写。

如两个Student的id、name、sex都一致,返回true.

@Override
public boolean equals(Object obj) {
    //将Object对象转换为当前类Student对象
    if (this == obj) {
        return true;
}
//判断参数是否为Student类型
//对象 instanceof 类 检测对象是否属于指定类型
    if (obj instanceof Student) {
        //使用"强制转换"将父类对象转换为子类对象,称为向下转型
        Student student = (Student) obj;
        if (this.id == student.id &&
            this.name.equals(student.name) &&
            this.sex.equals(student.sex)) {
            return true;
        }
    }
    return false;
}

在IDEA中自动生成equals方法

在类中右键generate或快捷键alt + insert,选择equals and hashcode,选择属性。

如两个对象的id相同就视为同一个对象,可以只选择id属性;

如两个对象的所有属性相同才视为同一个对象,选择全部属性。

同时生成的hashcode()可以删除

面向对象三大特性--多态

子类的对象保存在父类的变量中。

父类 变量 = new 子类();

public class Father{

}

public class Son extends Father{

}

public class Test{
    public static void main(String[] args){
        //多态:子类的对象保存在父类的变量中
        Father f = new Son();
    }
}

多态的应用

当某个方法的参数为父类变量时,可以传递一个子类对象。

这样就能在传递不同的子类对象时,表现出不同的形态。

如 要定义动物发出叫声的方法,参数是猫,输出猫对象的叫的方法"喵喵",参数是狗,输出狗对象的叫

的方法"汪汪"。

不用多态,需要写很多重载的方法,参数为猫或狗或其他类型。

使用多态,只需一个方法,参数为动物类,在动物类中定义叫的方法,让子类猫类狗类对其进行重写。

这时调用动物的叫的方法,实际会根据动物子类对象,调用具体子类重写后的方法。

多态的前提

在继承关系中

父类的变量保存子类的对象(向上转型)

作业模拟游戏厅

玩家类

package com.hqyj.homework;

import java.util.Objects;

/*
 * 玩家类
 * 属性
 *   用户名
 *   密码
 *   余额
 * */
public class Player {
    private String name;
    private String password;
    private double balance;


    /*
    * 如果用户名和密码相同,equals比较结果为true
    * */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Player player = (Player) o;
        return Objects.equals(name, player.name) && Objects.equals(password, player.password);
    }


    @Override
    public String toString() {
        return "Player{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", balance=" + balance +
                '}';
    }

    /*
     * 只包含用户名和密码的构造方法,用于登录
     * */
    public Player(String name, String password) {
        this.name = name;
        this.password = password;
    }

    /*
     * 全参构造,用于给所有参数赋值
     * */
    public Player(String name, String password, double balance) {
        this.name = name;
        this.password = password;
        this.balance = balance;
    }

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
}

游戏类

package com.hqyj.homework;

/*
 * 游戏类
 * 属性
 *
 * 方法
 *   开始游戏
 *
 * */
public abstract class Game {


    /*
     *  游戏父类,定义玩游戏的方法,参数为玩家对象
     * 如果一个方法没有方法体,可以将其定义为抽象方法,在返回值前使用abstract修饰
     * 如果一个类中有抽象方法,这个类必须是抽象类,类名前使用abstract修饰
     * */
    public abstract void start(Player player);
}

游戏子类

package com.hqyj.homework;

import java.util.Random;
import java.util.Scanner;

/*
 * 游戏子类:石头剪刀布
 * */
public class GameDemo extends Game {

    @Override
    public void start(Player player) {
        //生成1-3的随机数代表电脑出拳石头、剪刀、布
        int com = new Random().nextInt(3) + 1;
        System.out.println("请出拳:1.石头\t2.剪刀\t3.布");
        Scanner sc = new Scanner(System.in);
        int input = sc.nextInt();
        if (input < 1 || input > 3) {
            System.out.println("请输入正确的数字");
            return;
        }
        //扣钱
        player.setBalance(player.getBalance()-2);
        //判断电脑出拳
        switch (com) {
            case 1:
                //判断玩家出拳
                if (input == 1) {
                    System.out.println("你出的是石头,电脑出的是石头,平局!");
                } else if (input == 2) {
                    System.out.println("你出的是剪刀,电脑出的是石头,你输了!");
                } else {
                    System.out.println("你出的是布,电脑出的是石头,你赢了!");
                    player.setBalance(player.getBalance()+4);
                }
                break;
            case 2:
                if (input == 1) {
                    System.out.println("你出的是石头,电脑出的是剪刀,你赢了!");
                    player.setBalance(player.getBalance()+4);
                } else if (input == 2) {
                    System.out.println("你出的是剪刀,电脑出的是剪刀,平局!");
                } else {
                    System.out.println("你出的是布,电脑出的是剪刀,你输了!");
                }
                break;
            case 3:
                if (input == 1) {
                    System.out.println("你出的是石头,电脑出的是布,你输了!");
                } else if (input == 2) {
                    System.out.println("你出的是剪刀,电脑出的是布,你赢了!");
                    player.setBalance(player.getBalance()+4);
                } else {
                    System.out.println("你出的是布,电脑出的是布,平局!");
                }
                break;
        }
    }
}

游戏子类

package com.hqyj.homework;

import java.util.Random;
import java.util.Scanner;

public class GuessNum extends Game {


    /*
     * 重写玩游戏的方法,实际是该类表示的游戏子类的具体玩法
     * */
    @Override
    public void start(Player player) {
        //随机1-100猜数
        int ans = new Random().nextInt(100) + 1;
        Scanner sc = new Scanner(System.in);
        while (true) {
            //判断余额
            if (player.getBalance() <= 0) {
                System.out.println("余额不足,请充值");
                break;
            }
            //扣钱
            double newBalance = player.getBalance() - 2;
            player.setBalance(newBalance);
            //开始游戏
            System.out.println("请猜数");
            int input = sc.nextInt();
            if (input > ans) {
                System.out.println("猜大了!");
            } else if (input < ans) {
                System.out.println("猜小了!");
            } else {
                System.out.println("猜对了!");
                //加钱
                player.setBalance(player.getBalance() + 10);
                break;
            }
        }
    }
}

游戏厅类

package com.hqyj.homework;

import java.util.Scanner;

/*
 * 游戏厅类
 * 属性
 *   玩家集合
 *
 * 方法
 *   注册
 *   登录
 *   玩游戏
 *   充值
 * */
public class GameHouse {
    //玩家对象数组
    private Player[] playerList = new Player[10];


    /*
     * 注册
     * */
    public boolean register(Player player) {
        //遍历当前玩家集合
        for (Player p : playerList) {
            //如果注册的玩家名称已存在,无法注册
            if (p != null && p.getName().equals(player.getName())) {
                System.out.println("该用户已存在");
                return false;
            }
        }
        //添加参数到数组中
        for (int i = 0; i < playerList.length; i++) {
            if (playerList[i] == null) {
                playerList[i] = player;
                System.out.println("注册成功");
                return true;
            }
        }
        System.out.println("人数已达上限");
        return false;
    }
    /*
     * 登录
     * 参数为只有账号密码的玩家对象
     * 返回值为null或有账号密码和余额的玩家对象
     * */
    public Player login(Player player) {
        for (Player p : playerList) {
            if (p != null && p.equals(player)) {
                //返回已存在的玩家对象
                return p;
            }
        }
        return null;
    }

    /*
    * 充值
    * */
    public void charge(Player player){
        System.out.println("请输入充值金额");
        Scanner sc = new Scanner(System.in);
        int money = sc.nextInt();
        if(money>0){
            player.setBalance(player.getBalance()+money);
        }else{
            System.out.println("不能是负数");
        }
    }

    /*
    * 玩家玩游戏
    * */
    public void playGame(Game game,Player player){
        game.start(player);
    }
}

程序入口Main方法

package com.hqyj.homework;

import java.util.Scanner;

public class Main {


    public static void main(String[] args) {
        Main main = new Main();
        main.menu();
    }


    Scanner sc = new Scanner(System.in);
    GameHouse gh = new GameHouse();
    /*
     * 系统菜单
     * */
    public void menu() {
        System.out.println("1.登录\t2.注册\t3.退出");
        switch (sc.nextInt()) {
            case 1:
                System.out.println("请输入用户名");
                String loginName = sc.next();
                System.out.println("请输入密码");
                String loginPwd = sc.next();
                //登录对象
                Player player = new Player(loginName, loginPwd);
                //登录后的对象
                Player login = gh.login(player);
                if (login == null) {
                    System.out.println("用户名或密码错误");
                } else {
                    //进入玩家菜单
                    playerMenu(login);
                }
                break;
            case 2:
                System.out.println("请输入用户名");
                String regName = sc.next();
                System.out.println("请输入密码");
                String regPwd = sc.next();
                //注册对象
                Player regPlayer = new Player(regName, regPwd);
                //调用注册
                gh.register(regPlayer);
                //注册成功,跳转到本方法
                break;
            case 3:
                System.exit(0);
                break;
        }
        menu();//递归调用
    }

    /*
     * 玩家菜单
     * */
    public void playerMenu(Player player) {
        System.out.println("1.查看个人信息\t2.充值\t3.玩游戏\t4.返回主界面");
        switch (sc.nextInt()) {
            case 1:
                System.out.println(player);
                break;
            case 2:
                gh.charge(player);
                break;
            case 3:
                //进入游戏菜单
                gameMenu(player);
                break;
            case 4:
                //调用主菜单
                menu();
                break;
        }
        playerMenu(player);
    }

    /*
    * 游戏界面
    * */
    public void gameMenu(Player player){
        System.out.println("1.猜数游戏\t2.猜拳游戏\t3.返回玩家界面");
        switch (sc.nextInt()) {
            case 1:
                GuessNum guessNum = new GuessNum();
                gh.playGame(guessNum,player);
                break;
            case 2:
                gh.playGame(new GameDemo(),player);
                break;
            case 3:
                //进入玩家菜单
                playerMenu(player);
                break;
        }
        gameMenu(player);
    }
}

abstract抽象的

修饰方法

使用:访问修饰符 abstract 返回值类型 方法名(参数列表);

如果一个方法的方法体无法描述,是由其子类进行重写后使用,可以将这个方法定义为抽象方法。

该方法就可以去掉方法体部分,该方法的所在类,也必须是一个抽象类,使用abstract修饰。

修饰类

使用:访问修饰符 abstract class 类名{}

如果一个类中有抽象方法,这个类必须也是一个抽象类。

//当一个类中有抽象方法时,这个类也必须是抽象类
public abstract class Fruit{
    //当一个方法没有方法体时,这个方法定义为抽象方法
    public abstract void eatIt();
}

abstract关键字特点

修饰类:被修饰的类称为抽象类

抽象类不能被实例化(不能创建对象);

抽象类中有构造方法,在创建其子类对象时自动调用。

抽象类中可以有普通方法,通过其子类对象主动调用。

抽象类中定义的所有抽象方法,子类要么全部进行重写,要么也定义为抽象类

修饰方法:被修饰的方法称为抽象方法

抽象方法没有方法体

抽象方法只能出现在抽象类中

abstract不能修饰构造方法和静态方法

抽象相关面试题

抽象类的特点?

  • 抽象类是使用abstract修饰的类,除了不能创建对象、能定义抽象方法外,与普通类一样。抽象方法的特点?

  • 抽象方法是使用abstract修饰的方法,没有方法体。非抽象子类必须要对父类中的抽象方法进行重写。

抽象类中有构造方法吗?

  • 有构造方法,但不是通过new该类对象时调用,而是在new其子类对象时自动调用。

执行某个类的构造方法时,一定会创建这个类的对象吗?

  • 不一定

  • 如果是普通类,在执行构造方法时,一定会创建对象

  • 如果是抽象类,在执行构造方法时,不会创建自身对象,只会创建其子类对象

接口interface

在Java中,数据类型分为基本类型和引用类型。

引用类型包含:数组、类和接口。

所以接口是一种数据类型,类似于类,在定义接口的时候,使用interface替换class。

由于Java是单继承,如果类A既要继承类B中的内容,也要继承类C中的内容时,

如果用"extends class名",只能选择一个类继承,

但使用implements interface名1,interface名2...就能同时"继承"多个"父类".这里的"父类"就是接口。

通常用extends表示类A继承类B,用implements表示类A实现接口A,接口B...

一个类可以同时implements实现("继承")多个接口。

extends和implements

类A extends 类B

类A当做类B的子类,称为继承

类A implements 接口A,接口B...

类A当做类B的实现类,称为实现

接口A extends 接口B

接口A继承接口B

类A extends 类B implements 接口A,接口B...

类A是类B的子类,同时也是接口A,接口B的实现类

什么时候使用接口

如果想要让某个类作为多个"类"的子类时,将这些"父类"定义为接口

如果某个类中的所有方法都是抽象方法时,将这个抽象类改为接口

定义接口

public interface 接口名{
    //接口中只能定义公开的静态常量并且要赋值

    //接口中的方法一般都是公开的抽象方法 public abstract ,如果要定义,默认就有这两个关键字
    //public abstract void fun();
    void fun();//这句话相当于上一句,默认接口中的抽象方法使用public abstract修饰
    //jdk1.8后,可以在接口中定义"默认"方法,使用default修饰的方法
    default void test(){

    }
    //jdk1.8后,可以在接口中定义静态方法,使用static修饰的方法
    staic void test2(){

    }
}

接口案例

USB接口

package com.hqyj.test3;

/*
* 定义USB接口
* 只需定义有哪些功能,无需实现。子类实现功能
*
* 方法
* 连接
* 退出
* */
public interface USB {

    //接口中定义的方法都是抽象方法,默认使用public abstract修饰,可以不写
    //public abstract void fun();
    void start();
    void stop();
    //接口中可以定义被default修饰的默认方法
    default void fun1(){
        System.out.println("接口中定义的默认方法");
    }
    //接口中可以定义被static修饰的静态方法
    static void fun2(){
        System.out.println("接口中定义的静态方法");
    }
    //接口中定义的属性是被public final static修饰,称为公共的静态常量,必须要有初始值
    public final static int num=5;

}

USB接口的实现类--鼠标类和键盘类

package com.hqyj.test3;
import java.io.Serializable;
/*
* 定义USB接口的实现类:鼠标类
* 接口的实现类只需实现接口中的抽象方法
* */
public class Mouse implements USB {

    @Override
    public void start() {
        System.out.println("鼠标接入");
    }

    /*
    * 抽象方法一定要重写
    * */
    @Override
    public void stop() {
        System.out.println("鼠标退出");
        //子实现类中直接访问父接口中的默认方法,选择性重写
        //fun1();
        //通过接口名直接访问接口中的静态方法,静态方法无法重写
        //USB.fun2();
    }
}

package com.hqyj.test3;
public class Keyboard implements USB {
    private String name;

    public Keyboard(String name) {
        this.name = name;
}
    @Override
    public void start() {
        System.out.println(name + "键盘接入");
    }
    @Override
    public void stop() {
        System.out.println(name + "键盘退出");
    }
}

使用接口的类--电脑类

package com.hqyj.test3;

/*
* 电脑类
* 方法
* 开机
* 启动USB设备
* 关机
* 停止USB设备
* */
public class Computer {

    /*
    * 开机
    * */
    public void powerOn(USB usb1, USB usb2) {
        System.out.println("电脑开机。。。");
        if (usb1 != null) {
            usb1.start();
        } else {
            System.out.println("当前USB1插槽没有设备");
        }
        if (usb2 != null) {
            usb2.start();
        } else {
            System.out.println("当前USB2插槽没有设备");
        }
    }
    public void powerOff(USB... usbs) {
        System.out.println("电脑关机。。。");
        //遍历可变参数
        for (USB usb : usbs) {
            usb.stop();
        }
    }
}

Main

package com.hqyj.test3;

/*
* 模拟电脑使用USB设备
* 主机都有"USB接口",定义主机类,定义一些方法,参数为"USB设备"
* 所有“USB设置”都有连接和退出功能
*
*
* */
public class Main {
    public static void main(String[] args) {

        Computer computer = new Computer();
        //接口对象无法实例化(无法创建对象)
        //USB usb = new USB();
        //创建接口的实现类对象,可以用自身接收,也可以用父接口变量接收
        Mouse mouse = new Mouse();
        USB keyboard = new Keyboard("罗技");
        computer.powerOn(mouse, keyboard);
        //可变参数的方法传递参数时,可以是任意数量个参数,但这些参数类型必须统一
        computer.powerOff(mouse,keyboard);
    }
}

抽象类和接口的异同

抽象类是一个类,用abstract class定义

  • 有构造方法,不能创建对象,在创建子类对象时自动调用父抽象类中的构造方法

  • 抽象类中可以有非抽象方法

  • 抽象类被子类继承时,用extends关键字。子类需要重写父抽象类中的所有抽象方法

  • 子类只能继承一个抽象类

  • 抽象类中可以定义成员变量

接口不是一个类,用interface定义

  • 没有构造方法,不能创建对象

  • 接口中定义抽象方法时,无需加public abstract修饰符

  • 接口中可以存在被default或static修饰的方法

  • 接口被子类实现时,用implements关键字。子类需要重写父接口中的所有抽象方法

  • 子类可以实现多个接口,用逗号隔开

  • 接口中定义的属性都是公共的静态常量,被public static final修饰,必须要有初始值

相同点

  • 接口和抽象类都无法创建对象

  • 接口的实现类和抽象类的子类,都需要重写抽象方法

接口是一个完全抽象类。JDK1.8之后可以在接口中定义有方法体(被default或static修饰)的方法。

static静态的

每次new创建一个对象,都会在堆空间中开辟一块区域,这个过程是需要花费时间和空间的。

在栈空间中,只会定义变量,保存堆空间中某块区域的地址。通过变量访问堆空间中对应地址的数据。

如果多个对象都有相同的属性或方法时,可以将这些公共的属性和方法使用static修饰,

让其成为静态数据,在类加载的时候就保存在静态区中

在不使用静态成员时

如上图的"重庆大学"这个字符串,每个对象都会使用,就可以将其使用static关键字,定义为静态属性。

静态属性或静态方法,在类加载时就会保存到内存中,无论是否创建对象都能访问,通过类名直接访

问。

使用静态成员时

概念

static是一个修饰符,可以修饰属性、方法、代码块。

被static修饰的内容,称为静态成员。静态成员在类加载时就保存到内中。

访问静态成员时,可以不用创建对象,直接通过类名访问。

如Math中的所有属性和方法,都是静态的,都通过Math直接访问。

定义和访问

public class DBUtil{
    //静态属性,通常配合public final定义为公共的静态常量
    public static final int NUM=5;

    //静态方法
    public static Connection getConn(){
        //连接数据库操作
        return conn;
    }
    //静态代码块
    static{
        //代码;
    }
}

public class Test{
    public static void main(String[] args){
        //静态属性和方法直接通过类名访问
        System.out.println(DBUtil.NUM);
        //调用静态方法或创建对象时,自动执行一次静态代码块
        DBUtil.getConn();
        //也可以通过对象访问静态成员,但通常通过类名访问
        new DBUtil().getConn();
    }
}

什么时候使用static

如果某个属性或方法被高度重用时,可以将其定义为static静态的。

这样这些属性和方法在类加载时就会加载到内存中,从而直接通过类名即可访问。

static特点

  • 静态方法中只能使用静态成员,不能使用非静态成员

public class Student{
    static String STR="静态成员变量";
    int num=123;

    public static void fun(){
        System.out.println(STR);//可以访问
        System.out.println(num);//不能访问
    }
}
  • 非静态方法中,可以访问非静态或静态成员

public class Student{
    static String STR="静态成员变量";
    int num=123;
    public void fun(){
        System.out.println(STR);//可以访问
        System.out.println(num);//可以访问
    }
}
  • 静态方法中不能使用this或super关键字

成员变量、局部变量、静态常量

成员变量:定义在类中的变量

成员变量随着对象的创建而存在,随着对象的回收而销毁。

作用范围在类内部,成员变量有初始值。

局部变量:定义在方法中的变量

局部变量随着方法的调用而存在,随着方法执行结束而销毁。

作用范围在方法内容,局部变量没有初始值,必须赋值后才能使用。

静态常量:被final、static修饰的成员变量

静态常量随着类加载而存在,随着类的销毁而销毁(通常程序运行结束).

作用范围在程序运行周期中,静态量有初始值,静态常量必须赋值。

public class ZOO {
    //静态常量
    public static final String ZOO_NAME = "重庆动物园";
    //成员变量
    private String address;
    public ZOO(String address) {
        this.address = address;
    }
    //静态方法
    public static void welcome() {
        //只能使用静态常量
        System.out.println("欢迎光临" + ZOO_NAME);
    }

    //成员方法
    public void sayHello(Animal animal) {
        //局部变量
        String str = "你好";
        System.out.println(ZOO_NAME + "中的" + animal.getType() + "打招呼说" +
str);
        System.out.println("地址:"+address);
    }
}

public class Animal {
    private String type;
    public Animal(String type){
        this.type=type;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}

public class Main {
    public static void main(String[] args) {
        ZOO.welcome();
        Animal bear = new Animal("棕熊");
        new ZOO("杨家坪").sayHello(bear);
    }
}

作业模拟游戏人物PK

游戏角色类

package homework;

import java.util.Objects;

/*
* 游戏角色类
* */
public class Hero {
    private String name;
    private String weapon;
    private String skill;
    private int hp=1000;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Hero hero = (Hero) o;
        return Objects.equals(name, hero.name) && Objects.equals(weapon, hero.weapon) && Objects.equals(skill, hero.skill);
    }



    @Override
    public String toString() {
        return "Hero{" +
                "name='" + name + '\'' +
                ", weapon='" + weapon + '\'' +
                ", skill='" + skill + '\'' +
                ", hp=" + hp +
                '}';
    }

    public Hero(String name, String weapon, String skill) {
        this.name = name;
        this.weapon = weapon;
        this.skill = skill;
    }

    public String getName() {
        return name;
    }

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

    public String getWeapon() {
        return weapon;
    }

    public void setWeapon(String weapon) {
        this.weapon = weapon;
    }

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public int getHp() {
        return hp;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }
}

召唤师类

package homework;

import java.util.Random;

public class HeroManager {


    private Hero[] heroes = new Hero[10];


    /*
     * 添加
     * 不能添加重复(姓名、武器、技能相同)人物
     * */
    public void addHero(Hero hero) {
        //是否重复
        for (Hero h : heroes) {
            if (h != null && h.equals(hero)) {
                System.out.println(hero.getName() + "已存在");
                return;
            }
        }
        //添加
        for (int i = 0; i < heroes.length; i++) {
            if (heroes[i] == null) {
                heroes[i] = hero;
                System.out.println("添加成功");
                return;
            }
        }
        System.out.println("人数已达上限");
    }

    /*
     * 查看所有
     * */
    public void showAll() {
        //定义用于标号的数字
        int i = 1;
        for (Hero hero : heroes) {
            if (hero != null) {
                //打印时添加标号   toString()方法将对象转换为字符串
                System.out.println(i++ + ":" + hero);
            }

        }
    }

    /*
     * 根据编号得到人物对象
     * */
    public Hero findById(int id) {
        //实际1对应下标0
        return heroes[id - 1];
    }


    Random rd = new Random();

    public void battle(int id1, int id2) throws InterruptedException {
        Hero h1 = findById(id1);
        Hero h2 = findById(id2);
        System.out.println("【" + h1.getName() + "】VS【" + h2.getName() + "】");

        while (true) {
            if(h1.getHp()<=0){
                System.out.println(h1.getName()+"已阵亡");
                break;
            }
            if(h2.getHp()<=0){
                System.out.println(h2.getName()+"已阵亡");
                break;
            }
            //休眠
            Thread.sleep(500);
            //根据数字判断谁发动技能
            int num = rd.nextInt(9) + 4;
            int hurt1 = rd.nextInt(51) + 100;
            int hurt2 = rd.nextInt(51) + 100;
            //双方
            if (num == 12) {
                //技能伤害
                System.out.println(h1.getName() + "使用" + h1.getWeapon() + "发动" + h1.getSkill() + ",对" + h2.getName() + "造成了" + hurt1 + "伤害");
                System.out.println(h2.getName() + "使用" + h2.getWeapon() + "发动" + h2.getSkill() + ",对" + h1.getName() + "造成了" + hurt2 + "伤害");
                h1.setHp(h1.getHp()-hurt2);
                h2.setHp(h2.getHp()-hurt1);
            }else if(num%3==0){//其中一方
                System.out.println(h1.getName() + "使用" + h1.getWeapon() + "发动" + h1.getSkill() + ",对" + h2.getName() + "造成了" + hurt1 + "伤害");
                h2.setHp(h2.getHp()-hurt1);
            }else if(num%4==0){//其中一方
                System.out.println(h2.getName() + "使用" + h2.getWeapon() + "发动" + h2.getSkill() + ",对" + h1.getName() + "造成了" + hurt2 + "伤害");
                h1.setHp(h1.getHp()-hurt2);
            }else{
                System.out.println(h1.getName() + "使用对" + h2.getName() + "进行普通攻击,造成了" + 10 + "伤害");
                System.out.println(h2.getName() + "使用对" + h1.getName() + "进行普通攻击,造成了" + 10 + "伤害");
                h1.setHp(h1.getHp()-10);
                h2.setHp(h2.getHp()-10);
            }
        }
    }
}

Main方法

package homework;

import java.util.Scanner;

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

        HeroManager hm = new HeroManager();

        Hero h1 = new Hero("吕布", "方天画戟", "毁天灭地");
        Hero h2 = new Hero("吕布", "方天画戟", "毁天灭地");
        Hero h3 = new Hero("貂蝉", "长袖", "跳舞");

        hm.addHero(h1);
        hm.addHero(h2);
        hm.addHero(h3);

        hm.showAll();

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入第一个人物的编号");
        int id1 = sc.nextInt();
        System.out.println("请输入第二个人物的编号");
        int id2 = sc.nextInt();
        hm.battle(id1, id2);

    }
}

可变参数

当某个方法的参数是同一种类型且数量未知时,参数列表中可以使用可变参数定义。

修饰符 返回值类型 方法名(数据类型... 形参名){
    //这时的参数的数量是可变的,[0,∞)
    //整个参数是一个数组
}

特点

可变参数只能出现一次,且是最后一个参数

可变参数实际是一个数组

调用参数为可变参数的方法时,传递的实参要使用逗号

public class Main {
    /*
    * 计算一些数字的总和
    * */
    public int getSum(int... nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        return sum;
    }
    public static void main(String[] args) {
        //
        Main main = new Main();
        //调用可变参数的方法,实参之间使用逗号隔开
        System.out.println(main.getSum(1,2,3,4));
    }
}

枚举

Java中的枚举是一个特殊的类,是一些常量的集合。

如星期可以用数字1-7表示,也可以用"周一到周天"表示,

也可以用SUN,MON,TUE,WED,THU,FRI,SAT这些来表示。

这三种都可以称为枚举,对星期这个概念进行枚举。

定义枚举类型

public enum 枚举类型名{
    常量1,常量2...常量N
}

使用枚举类型

枚举类型名.常量名;
package test1;
/*
* 定义枚举类型
* 使用enum关键字替换class
* 枚举是一个特殊的"类",
* 将某个事物使用指定的内容进行一一例举
* */
public enum Week {
    //定义一组枚举类型的常量集合
    SUN,MON,TUE,WED,THU,FRI,SAT
}
package test1;

public class Main {
    public static void main(String[] args) {
        //遍历自定义的枚举类型
        //for (Week value : Week.values()) {
        // System.out.println(value);
        //}
        System.out.println("请输入星期的简写");
        Scanner sc = new Scanner(System.in);
        String input = sc.next();

        //根据字符串获取对应的枚举数据
        Week week = Week.valueOf(input);
        //判断枚举类型
        switch (week) {
            case SUN:
                System.out.println("星期天");
                break;
            case MON:
                System.out.println("星期一");
                break;
            case TUE:
                System.out.println("星期二");
                break;
            case WED:
                System.out.println("星期三");
                break;
            case THU:
                System.out.println("星期四");
                break;
            case FRI:
                System.out.println("星期五");
                break;
            case SAT:
                 System.out.println("星期六");
                 break;
            default:
                 System.out.println("单词有误");
        }
    }
}

内部类

内部类,是指定义在类中的类。

内部类通常使用private修饰,定义在类中,用于隐藏类的实现细节,将类进行封装

public class Outer{
    //内部类通常private私有化,只能当前外部类中才能使用
    private class Inner{
        //这就是一个内部类
        //这里可以定义属性和方法
    }
}

内部类分为:成员内部类,静态内部类,局部内部类和匿名内部类。

匿名内部类

没有名称的内部类称为匿名内部类。

当某个方法的参数为接口或抽象类对象时,通常会先定义接口的实现类或抽象类的子类,再创建子类对象作为方法的参数。

如果使用匿名内部类,就可以不用创建子类,而是直接通过匿名内部类作为参数使用。

Lambda表达式

JDK8中的核心升级点。

通常用于简化匿名内部类的写法。

要简化的匿名内部类必须是函数式接口(只有一个抽象方法的接口)。

Lambda表达式语法

(参数类型 参数名) -> {代码语句;}

小括号部分表示参数列表

->部分表示要执行什么

{}部分表示执行的内容

使用lambda表达式遍历集合

面向过程和面向对象编程思想

面向过程POP:所有步骤按顺序执行,注重执行的细节。

面向对象OOP:创建解决问题的对象,让各个对象调用各自的方法而配合完成。

在面向对象编程OOP中,给类中定义的方法,具体的实现过程,其实也是面向过程的。

对象和类

对象Object

某个类的具体实例

类Class

是拥有相同属性和行为的对象的集合。是对象的模板。

定义类

修饰符 class 类名{
    //属性:定义变量
    //行为:定义方法
}

类中的属性

成员变量、局部变量、静态常量

成员变量:定义在类中的变量,即类的属性。它有默认值。通过对象访问。

局部变量:定义在方法中的变量。它没有默认值。只能在方法中赋值后才能使用。

静态常量:特殊的成员变量,用final static修饰。它有默认值。通过类名访问。

类中的方法

  • 构造方法

  • 成员方法

  • 静态方法

class Person{
    //成员变量
    String name;
    //静态常量
    final static String COUNTRY="中国";
    //构造方法
    public Person(String name){
    this.name=name;
    }
    //成员方法
    void info(){
        //局部变量
        String address="悉尼";
        System.out.println("我叫"+name+",来自于"+COUNTRY+",现居住"+address);
    }
    //静态方法
    public static void fun(){
    }
}

创建对象

类名 变量名 = new 构造方法([参数]);

构造方法

是一种特殊的方法。方法名和类名一致,没有返回值部分。

访问修饰符 类名(数据类型 参数名称){

}
  • 没有返回值部分,方法名必须和类名一致。

  • 在使用new关键字创建对象时,调用对应的构造方法。

  • 每个类在定义后,都隐藏有一个无参的构造方法。

  • 如果自定义了有参数的构造方法,无参数的构造方法就会失效。如果想要使用无参构造方法,就要再写出来。

  • 构造方法通常用于限制创建对象时携带的参数,初始化成员变量。

  • 构造方法之间都是重载关系,构造方法不能重写。

  • 构造方法执行时,不一定会创建对象。如抽象类中有构造方法,但无法创建抽象类对象,只能在创建抽象类的子类对象时,自动调用抽象类的构造方法

面向对象三大特性

封装

将类中的属性使用private修饰,这样就能防止非当前类对其访问,隐藏类中的关键属性。

通常会对private修饰的属性提供公开的get和set方法用于获取和赋值。

继承

类A extend 类B。

接口A extends 接口B。

前者就是后者的子类,前者的对象就能直接访问后者中非私有成员。

重写Override

子类继承父类后,对父类中的非私有方法进行重写,达到拓展或重做的目的

必须满足方法名、返回值、参数列表都相同

访问权限不能比父类中的方法更严格

不能抛出比父类中的方法更大的异常

重载Overload

在一个类中,某个方法在不同的参数下,表现不同的行为。同名不同参。

方法名必须相同

参数列表必须不同(类型和数量)

无返回值无关

this和super

都可以当做对象后构造方法使用。

当做对象:this表示当前类的对象,super当前类的父类对象。

this或super当做对象使用时,只能用在非静态方法中。

当做构造方法

this()表示当前类中无参构造方法,如果带参数就表示对应参数的构造方法

super()表示当前类的父类的无参构造方法,如果带参数就表示对应参数的构造方法

this()或super()只能用在另一个构造方法的首行。

在继承后,如果子类和父类都没有写出任何构造方法时,子类中有一个隐藏的无参构造方法,会自动调

用父类的无参构造方法

public class Father{

}
public class Son extends Father{
    /*
        会有这段代码
    */
    public Son(){
        super();
    }
}

所以如果在父类中定义了有参数的构造方法,无参构造方法就会失效,子类必须调用父类中的有参数的

构造方法

public class Father{

    String name;
    public Father(String name){
        this.name=name;
    }
}
public class Son extends Father{
    /*
        必须要调用super(String name)
    */
    public Son(String name){
        super(name);
    }
}

Object类

是所有类的父类。任何类都间距地继承了Obejct类。所以所有类都能访问Object类中的方法,都可以进

行重写。

toString()是Object类中的一个方法,在输出对象时自动调用。

默认输出"类全限定名@十六进制哈希码"。通常在自定义的实体类中,重写toString(),输出当前类的属性。

equals()是Object类中的一个方法,用于比较两个对象是否相同。

默认使用==比较内存地址。通常在自定义的实体类中,重写equals(),自定义比较的规则。

hashCode()是Object类中的一个方法,用于获取对象的哈希码。

默认使用全部参数生成哈希码。可以重写自定义生成哈希码的参数。

对象转型

类似于原始类型间的数据类型转换

向上转型:父类变量 = 子类对象;

类似于自动类型转换

Person p = new Person();
Object obj = p;

向下转型: 子类变量 =(子类) 父类对象;

类似于强制类型转换

Animal anl = new Animal();
Cat c = (Cat) anl;

多态

在继承关系中,子类的对象可以保存到父类的变量中。(向上转型)

多态常用与定义方法时,形参为一个父类或接口类型变量,实参为子类对象。

无法通过父类变量调用子类中独有的方法。如果调用重写了父类中的方法时,执行重写后的内容。

父类/父接口 对象 = new 子类();

public class Father{
    public void smoking(){
        System.out.println("Father is smoking");
    }
}

public class Son extends Father{
    public void play(){
        System.out.println("Son is playing");
    }

    public void smoking(){
    System.out.println("Son is smoking");
    }
}

public class Test{

    public static void main(String[] args){
        Father father = new Son();
        //可以访问
        father.smoking();//输出Son is smoking
        //无法访问
        //father.play();
    }
}

修饰符

访问修饰符

final

修饰属性

变量变为常量,定义时就要赋值,程序运行过程中不能改变其值。

修饰方法

方法成为最终方法,不能重写。

修饰类

类为最终类,不能被继承。

abstract

  • 修饰方法

方法为抽象方法,没有方法体。同时所在的类也需要使用abstract定义为抽象类

  • 修饰类

抽象类不能创建对象

抽象类除了能定义抽象方法外,其余与普通类无区别

抽象类中可以有构造方法,在创建其子类对象时自动调用

抽象类通常需要被继承,一旦有子类继承,子类就要重写抽象父类中的所有抽象方法,或者子类也是一个抽象类

interface

用于定义接口的关键字。代替class,能让java实现"多继承"。

如果某个抽象类中的所有方法都是抽象方法时,可以将该类改为接口。

abstract class --> interface

接口是一个完全抽象类,其中的方法都是public abstract修饰的抽象方法,其中的属性都是public

final static修饰的静态常量。

接口中没有构造方法,不能创建对象

接口通过implements“继承”。类A implements 接口A,接口B,称为类A实现了接口A和接口B,一

个类可以"继承"多个父接口

一个类一旦实现了某个接口,就要重写其中的所有抽象方法

JDK1.8后,可以在接口中定义default或static修饰的方法,该方法不用重写。

static

被static修饰的内容称为静态成员

静态成员在类加载时就会保存到内存中,所以访问时通过类名直接访问。

当某个属性或方法被高度重用时,将其定义为静态的,之后通过类名方便调用。

修饰方法

public static void fun(){

}

修饰属性

public static final int NUM=123;

定义代码块

static{
    //在调用该类中的方法或创建对象时自动执行一次
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值