【JAVA笔记】

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

Java中标识符的命名规则

标识符

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

标识符命名规范

帕斯卡命名法

所有单词首字母大写
如StudentInfomation、Employee、ClassName

驼峰命名法

第一个单词首字母小写,其余单词首字母大写
如studentInfomation、employee、className

类名使用帕斯卡命名法
方法名、变量名使用驼峰命名法

变量命名的要求

1)使用字母、数字、下划线或$符号组成
2)不能使用数字开头
3)不能使用关键字
4)见名知意

方法

方法是定义在类中的一段独立代码,能完成某个事情。
定义方法时,提供方法的名称、返回值类型、参数列表,这三点称为方法三要素,定义的方法都需要这
三部分。
当再使用该方法中的代码时,只需通过该方法名调用即可。
方法能够减少代码冗余。

调用方法

1通过类名调用

Math类

Math类是Java中的工具类,用于数学计算。
该类中的方法和属性都使用static修饰的,可以直接通过类名调用。
在任何类中,通过快捷键alt+7,展示方法列表

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

2通过对象调用

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

Scanner sc = new Scanner(System.in);
sc.方法名();
Random rd = new Random();
rd.方法名();

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

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

方法调用总结

调用方式

  1. 通过类名调用
  2. 通过对象调用
  3. 直接调用

参数

  1. 无参数
Scanner sc = new Scanner(System.in);
sc.next();//调用无参数方法
  1. 有参数
Random rd = new Random();
rd.nextInt(10);//调用有参数方法

返回值

1.没有返回值,方法名的前面用void表示

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

自定义方法

方法三要素

方法名

1 )使用驼峰命名法

方法返回值类型

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

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

方法参数列表

1)参数写法:数据类型 形参名,数据类型 形参名

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

方法类型

有参数无返回值

void 方法名(){
//方法体
return;//遇到return立即结束方法
}

无参数有返回值

int 方法名(){
return new Random().nextInt();
}

有参数无返回值

void 方法名(数据类型 形参名,数据类型 形参名){
//方法体
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一个该方法返回值类型
    对应的数据。
  2. 没有返回值的方法,可以不用加入return关键字。如果加入return关键字,不能跟上数据。
  3. 方法中出现return,会立即结束方法。所以return语句之后不能再有代码。
  4. 定义方法时的参数称为形式参数,简称形参;调用方法时,实际传递的参数称为实际参数,简称实
    参。实参只需保证数据类型和形参相同即可。

编程思想

面向过程编程

Procedure Oriented Programming 简称POP
是一种基本的编程思想,将一件事情按流程按步骤执行,逻辑清晰。
每一步都是基于上一步的流程去继续实现。
注重于分析问题的步骤。
如果逻辑复杂,如xxx管理系统,使用POP就会变得很麻烦。
C语言就是一门面向过程的编程语言。

面向对象编程

Object Oriented Programming 简称OOP
是一种编程思想,核心是创建解决问题的对象,赋予对象行为和特征,让这些对象互相配合执行。
每个对象的行为实际也是面向过程的。
注重于全局如何创建完成某件事情的对象,如果适时地调用。
这种思想致力于将计算机中的世界,描述的和现实中一致的思想。
如洗衣服
pop:得到衣服–得到洗衣服–洗–晾晒
oop:得到衣服对象 、得到洗衣机对象、调用洗衣机对象的洗衣服行为

总结

  1. 面向过程:亲力亲为,侧重于分析完成事情的过程
  2. 面向对象:所有事情交给相应的对象完成,侧重于如何创建解决问题的对象

类和对象

Class

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

1.属性:描述这个类的特征值,在程序中,通过定义变量实现。
2.行为:描述这个类的动作,在程序中,通过定义方法实现。
创建一个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

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

创建对象

1)类名 对象名 = new 构造方法([参数]);
2)创建出的对象,通过"."操作符访问类中的非私有属性和方法。

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();
}
}

类和对象的关系

对象是类的具体表现,类是对象的模板。
如制作月饼的模具就是一个类,每次用这个模具创建出来的月饼就是一个对象。
先定义类,才能通过该类获取对象。

成员变量和局部变量

成员变量

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

在这里插入图片描述

class Person{
String name;//成员变量,String是类类型,属于引用类型,默认为null
int age;//整型,默认0
double[] list;
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);//无法通过编译
}
}
成员变量和局部变量相关面试题
简述成员变量和局部变量的区别以及生命周期。

1:成员变量定义在类中。有默认值,不赋值也可以使用。
2:局部变量定义在方法中,没有默认值,要赋值才可以使用。
3:成员变量生命周期:类创建对象,成员变量就会被初始化,类的对象被回收,成员变量就会销毁。
4:局部变量的生命周期:方法调用,局部变量赋值,局部变量初始化,方法调用结束,局部变量失效。

构造方法

概念

构造方法也称为构造函数、构造器、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配合构造方法
  2. 构造方法可以存在多个,但是参数不能相同。这些构造方法之间的关系称为方法重载
  3. 每个类默认有一个隐藏的无参数的构造方法,方法体中隐含了一句super()。用于创建无参数的对象
  4. 如果自己写了带参数的构造方法,默认无参数的构造方法就会失效。如果想要同时拥有带参数和不带参数的构造方法,就需要再次显式地写出来
  5. 带参数的构造方法常用于初始化成员变量(给类中的变量赋值)
  6. 构造方法可以限制创建对象时携带的参数
  7. 构造方法无法通过"."操作符访问,只能通过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;
}

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

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
整段代码 ```语言

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

功能:

实现对图书的添加、修改、删除、查询功能
  1.  如何保存多个图书?
    

采用图书数组保存
2) 如何实现添加?
判断数组是否有空元素(元素==null),如果有,将参数对象保存
3) 如何实现删除?
遍历数组,根据参数编号循环比较,如果满足相等,用null覆盖
4) 如何实现查询?
查询所有
遍历数组,空元素无需打印
查询单个
根据编号与数组中的元素遍历比较,满足时返回对应的对象
5) 如何实现修改?
调用查询单个的方法,得到编号对应的对象,使用set方法对某个属性赋值

图书类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;
//用于输出对象时自动调用
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
", type='" + type + '\'' +
", publisher='" + publisher + '\'' +
", price=" + price +
'}';
}
//封装:getter/setter
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;
}
//无参数的构造方法
public Book() {
}
//全部参数的构造方法
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;
}
}

管理员类Manager

package test4;
/*
* 图书管理员类
* 属性
* 保存图书的容器
*
*
* 方法
* 增 添加图书
* 删 删除图书
* 改 修改图书
* 查 查看图书
*
* */
public class Manager {
//保存图书对象的容器,该属性只能当前类使用,使用private修饰,不提供get/set
private Book[] bookList = new Book[10];
//添加
void addBook(Book book) {
for (int i = 0; i < bookList.length; i++) {
//如果存在空位,将参数保存在该位置上
if (bookList[i] == null) {
bookList[i] = book;
//停止循环,防止装满
break;
}
}
}
//查看所有图书
void showAll() {
System.out.println("编号\t书名");
for (Book book : bookList) {
if (book != null) {
//只显示编号和书名
System.out.println(book.getId()+"\t"+book.getName());
}
}
}
/*
* 根据id修改价格
* */
void update(int id,double newPrice){
//根据id得到对应的图书
//调用当前类中定义的根据id查询Book对象的方法
Book book = getBookById(id);
//判断是否得到
if(book!=null){
book.setPrice(newPrice);
}else{
System.out.println("图书不存在");
}
}
/*
* 根据图书编号删除
* */
void delete(int id) {
//遍历数组
for (int i = 0; i < bookList.length; i++) {
//bookList[i]是数组中的某个book对象
//如果该对象不为空,获取其id与参数判断
if(bookList[i]!=null && bookList[i].getId()==id){
//使用null覆盖,实现删除
bookList[i]=null;
break;
}
}
}
/*
* 根据id得到对应的图书对象
* */
Book getBookById(int id) {
//遍历当前所有的图书对象
for (Book book :bookList) {
//如果遍历出的对象不为空,得到对应的id与参数判断
if (book!=null && book.getId()==id) {
//返回对应的图书
return book;
}
}
//如果遍历未发现满足条件,返回null
return null;
}
}

程序人口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.退出");
switch (sc.nextInt()) {
case 1:
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("请输入价格");
double price = sc.nextDouble();
//创建一个图书对象
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("请输入要修改的价格");
double newPrice = sc.nextDouble();
manager.update(updateId, newPrice);
break;
case 3:
System.out.println("请输入要删除的编号");
manager.delete(sc.nextInt());
break;
case 4:
manager.showAll();
break;
case 5:
System.out.println("请输入要查看的编号");
System.out.println(manager.getBookById(sc.nextInt()));
break;
case 6:
System.exit(0);
break;
}
}
}
}

面向对象三大特性

1继承

概念

类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继承这个父类,那些类就是子类。子类就无需再写重复代码
  2. 子类中或子类对象可以直接访问父类中非私有(不用private修饰)属性和方法
  3. 创建子类对象时,会先执行父类中相应的构造方法
  4. 子类继承父类后,通常会对对父类中的方法进行拓展或覆盖,这称为方法重写。重写后,子类再调
    用该方法时,执行的是重写后的内容
  5. Java中是单继承。一个子类只能extends一个父类,一个父类可以有很多子类
  6. Java中可以多重继承,类A可以继承类B,类B继承类C,这是类A既是类B的子类,也是类C的子
    类,类A可以访问类B和类C中的非私有成员
  7. 任何类都是Object类的子类

方法重写和方法重载

方法重写override

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

方法重写要求

  1.  方法名、返回值、参数列表必须和父类一致
    
  2.  访问权限不能比父类更严格(访问修饰符的范围要么一致要么更大)
    
  3.  不能抛出比父类更大的异常
    

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

方法重载overload

在一个类中,如果多个方法的方法名相同,参数列表不同时,这些方法称为重载的方法。
同名不同参*
重载用于,在一个类中,某个方法在不同的条件下,执行不同的内容。

方法重载要求

1) 方法名相同
2)参数必须不同(数量、类型)
3) 与返回值无关

重载和重写相关面试题

1)说出重载与重写的异同:
相同点:方法名不变
不同点:
重载在一个类中,重写在继承关系中子类重写父类
重载参数必须不同,重写参数必须相同
重载返回值无要求,重写返回值必须相同
2)构造方法能重载吗?能重写吗?
构造方法可以重载。构造方法不能重写。
构造方法在执行时,一定会创建对象吗?
不一定。创建子类时会自动执行父类构造方法,但不会创建父类对象。
3) 以下代码执行会输出什么结果

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

1)通过包可以将.java源文件进行结构化管理,相当于windows中的文件夹。
2) 不同的包中,可以保存相同的.java源文件
3)某个类在某个包中时,会在该类的代码最上加入package包名

包的命名

包名通常所有公司域名倒序的形式
如baidu.com是百度的域名,有一个test的项目,包名写为com.baidu.test
包名中的".",相当于进入文件夹
如com.baidu.test,会创建3个文件夹:com下有baidu,baidu下有test。

导入包

1) 如果A包中的类要使用B包中的类时,需要在A包中的类导入B包中的某个类。
2) 如在使用Scanner时,就需要导入Scanner所在的java.util包。 import java.util.Scanner;
3) 在IDEA中,如果是通过自动补全的形式写的代码,会自动导入该类,或设置自动导包删包。
在这里插入图片描述
如果需要手动导入包,在报错的位置上按下快捷键alt+回车,
如果多个类,类名相同但在不同的包中,使用该类时选择合适的包。

访问修饰符

访问修饰符可以限制某个类、属性或方法的访问权限
用法:
修饰类:访问修饰符 class 类名{}
修饰属性:访问修饰符 数据类型 变量名;
修饰方法:访问修饰符 返回值类型 方法名(){}
在这里插入图片描述

访问权限表

在这里插入图片描述
访问权限从大到小
public >>> protected >>> 默认的 >>> private

final关键字

修饰属性

1) 当final修饰属性时,该属性的值不可以更改,这个属性称为常量
2) 常量在程序运行的过程中,保存的值不能骗号,所以定义常量时需初始化
3) 常量名所有的字母大写,多个单词之间用_隔开

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类

1) 是java中所有类的父类。每个类都是这个类的子类,但没有使用extends体现出来
2) 该类中定义了很多方法,通常需要进行重写。
在这里插入图片描述

对象造型/对象转型/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()可以删除。

Manager类
package com.hqyj.test3;
import java.util.Objects;
/*
* 登录系统的管理员类
* 属性
* 账号
* 密码
* 方法
* 全参构造
* 无参构造
* getter/setter
* toString
* equals
* */
public class Manager {
private String username;
private String password;
@Override
public String toString() {
return "Manager{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
//判断是否是同一个对象
if (this == o) return true;
//是否为空,是否属于同一种类
if (o == null || getClass() != o.getClass()) return false;
//向下转型
Manager manager = (Manager) o;
//遍历所有属性判断是否一致
//Objects是一个工具类,equals()方法判断两个参数是否相同,实际使用参数的equlas方法判return Objects.equals(username, manager.username) &&
Objects.equals(password, manager.password);
}
public Manager() {
}
public Manager(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Shop类
package com.hqyj.test3;
/*
* 属性
* 管理员列表
* */
public class Shop {
//管理员列表
private Manager[] managers = new Manager[5];
/*
* new Shop();
* 定义无参构造方法,在创建当前类对象的同时,在数组中保存一个Manager对象
* */
public Shop() {
managers[0] = new Manager("admin", "123123");
}
/*
* 注册
* 实际是添加,将参数创建为完整对象,添加到数组中
* */
public boolean register(String name, String pwd) {
//判断用户名是否存在
for (Manager manager : managers) {
if (manager != null && manager.getUsername().equals(name)) {
System.out.println("该用户名已存在");
return false;
}
}
//将参数包装为一个完整对象
Manager manager = new Manager(name, pwd);
//保存到数组
for (int i = 0; i < managers.length; i++) {
if(managers[i]==null){
managers[i]=manager;
System.out.println("注册成功");
return true;
}
}
System.out.println("人数超过上限");
return false;
}
/*
* 登录
* */
public boolean login(String name, String pwd) {
//将登录时输入的账号密码封装为一个对象
Manager loginManager = new Manager(name, pwd);
面向对象三大特性--多态
子类的对象保存在父类的变量中。
父类 变量 = new 子类();
多态的应用
当某个方法的参数为父类变量时,可以传递一个子类对象。
这样就能在传递不同的子类对象时,表现出不同的形态。
如 要定义动物发出叫声的方法,参数是猫,输出猫对象的叫的方法"喵喵",参数是狗,输出狗对象的叫
的方法"汪汪"。
不用多态,需要写很多重载的方法,参数为猫或狗或其他类型。
使用多态,只需一个方法,参数为动物类,在动物类中定义叫的方法,让子类猫类狗类对其进行重写。
这时调用动物的叫的方法,实际会根据动物子类对象,调用具体子类重写后的方法。
//遍历管理员列表
for (Manager manager : managers) {
//如果有对象的参数和当前方法参数一致,说明登录成功
//if (manager != null && manager.getUsername().equals(name) &&
manager.getPassword().equals(pwd)) {
//调用重写后的equasl方法,如果两个对象的所有参数一致,视为同一个对象
if (loginManager.equals(manager)) {
return true;
}
}
return false;
}
}

面向对象的三大特性

1多态

子类的对象保存在父类的变量中
父类 变量()=new 子类();

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

多态的应用

当某个方法的参数为父类变量时,可以传递一个子类对象。
这样就能在传递不同的子类对象时,表现出不同的形态。
如 要定义动物发出叫声的方法,参数是猫,输出猫对象的叫的方法"喵喵",参数是狗,输出狗对象的叫
的方法"汪汪"。
不用多态,需要写很多重载的方法,参数为猫或狗或其他类型。
使用多态,只需一个方法,参数为动物类,在动物类中定义叫的方法,让子类猫类狗类对其进行重写。
这时调用动物的叫的方法,实际会根据动物子类对象,调用具体子类重写后的方法

多态前提

1) 在继承关系中
2) 父类的变量保存在子类的对象

多态应用案例–“花木兰替父从军”

Woman类
package com.hqyj.test5;
/*
* 女人类
* */
public class Woman extends Soldier{
private String name;
public Woman(String name) {
this.name = name;
}
@Override
public void fight() {
System.out.println(name+"假装军人上场");
}
//做家务
public void doHouseWork() {
System.out.println(name + "烧水做饭");
}
//打扮
public void makeup() {
System.out.println(name + "梳妆打扮");
}
}
Soldier类
package com.hqyj.test5;
/*
* 军人类
* */
public class Soldier {
private String name;
private String weapon;
public Soldier(String name, String weapon) {
this.name = name;
this.weapon = weapon;
}
BattleGround类
Main
public Soldier() {
}
/*
战斗的方法
*/
public void fight() {
System.out.println(name + "使用" + weapon + "上阵杀敌");
}
}
BattleGround类
package com.hqyj.test5;
/*
* 战场类
* */
public class BattleGround {
//战争,参数为军人,调用战斗的方法
public void war(Soldier soldier){
soldier.fight();
}
}
Main类
package com.hqyj.test5;
public class Main {
public static void main(String[] args) {
//创建战场对象
BattleGround bg = new BattleGround();
//创建军人对象,其中有fight方法
//Soldier soldier = new Soldier("花爸爸", "AK47");
//调用战场对象的war方法,参数为军人对象
//bg.war(soldier);//输出soldier中的内容
//创建女人对象
//Woman woman = new Woman("花木兰");
//正常调用女人对象的方法
//woman.doHouseWork();
//woman.makeup();
//假设无法再创建Soldier对象
//将Woman类继承Soldier类,"替父从军",重写fight方法
//这样就能将子类对象当做父类对象来使用,这就是多态
Soldier woman = new Woman("花木兰");
//最终表现的就是实际传递的子类的行为
bg.war(woman);
//子类使用父类变量接收后,只能调用父类中的方法,无法调用子类的方法
//woman.makeup();
//woman.doHouseWork();
}
}

abstract抽象的

修饰方法

使用:访问修饰符 abstract 返回值类型 方法名(参数列表);
如果一个方法的方法体无法描述,是由其子类进行重写后使用,可以将这个方法定义为抽象方法。
该方法就可以去掉方法体部分,该方法的所在类,也必须是一个抽象类,使用abstract修饰。

修饰类

使用:访问修饰符 abstract class 类名{}
如果一个类中有抽象方法,这个类必须也是一个抽象类。

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

abstract关键字特点

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

1) 抽象类不能被实例化(不能创建对象);
2) 抽象类中有构造方法,在创建其子类对象时自动调用。
3) 抽象类中可以有普通方法,通过其子类对象主动调用。
4) 抽象类中定义的所有抽象方法,子类要么全部进行重写,要么也定义为抽象类。

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

  1.  抽象方法没有方法体
    
  2.  抽象方法只能出现在抽象类中
    
  3.  abstract不能修饰构造方法和静态方法
    

抽象相关面试题

  1.  抽象类的特点?
    

抽象类是使用abstract修饰的类,除了不能创建对象、能定义抽象方法外,与普通类一样。
2) 抽象方法的特点?
抽象方法是使用abstract修饰的方法,没有方法体。非抽象子类必须要对父类中的抽象方法进
行重写。
3) 抽象类中有构造方法吗?
有构造方法,但不是通过new该类对象时调用,而是在new其子类对象时自动调用。
40 执行某个类的构造方法时,一定会创建这个类的对象吗?
不一定
如果是普通类,在执行构造方法时,一定会创建对象
如果是抽象类,在执行构造方法时,不会创建自身对象,只会创建其子类对象

接口interface

  1.  在Java中,数据类型分为基本类型和引用类型。
    
  2.  引用类型包含:数组、类和接口。
    
  3.  所以接口是一种数据类型,类似于类,在定义接口的时候,使用interface替换class。
    
  4.  由于Java是单继承,如果类A既要继承类B中的内容,也要继承类C中的内容时,
    
  5.  如果用"extends class名",只能选择一个类继承,
    
  6.  但使用implements interface名1,interface名2...就能同时"继承"多个"父类".这里的"父类"就是接口。
    
  7.  通常用extends表示类A继承类B,用implements表示类A实现接口A,接口B...
    
  8.  一个类可以同时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的实现类

什么时候使用接口

  1.  如果想要让某个类作为多个"类"的子类时,将这些"父类"定义为接口
    
  2.  如果某个类中的所有方法都是抽象方法时,将这个抽象类改为接口
    

定义接口

public interface 接口名{
//接口中只能定义公开的静态常量并且要赋值
//接口中的方法一般都是公开的抽象方法 public abstract ,如果要定义,默认就有这两个关键字
//public abstract void fun();
void fun();//这句话相当于上一句,默认接口中的抽象方法使用public abstract修饰
//jdk1.8后,可以在接口中定义"默认"方法,使用default修饰的方法
default void test(){
}
//jdk1.8后,可以在接口中定义静态方法,使用static修饰的方法
staic void test2(){
}
}

接口ge

USB接口

package com.hqyj.test3;
/*
* 定义USB接口
* 只需定义有哪些功能,无需实现。子类实现功能
*
* 方法
* 连接
* 退出
* */
public interface USB {
//接口中定义的方法都是抽象方法,默认使用public abstract修饰,可以不写
//public abstract void fun();
void start();
void stop();
USB接口的实现类--鼠标类和键盘类
//接口中可以定义被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;
}
使用接口的类--电脑类
Main
@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定义

1) 有构造方法,不能创建对象,在创建子类对2) 象时自动调用父抽象类中的构造方法
3) 抽象类中可以有非抽象方法
4) 抽象类被子类继承时,用extends关键字。子类需要重写父抽象类中的所有抽象方法
5) 子类只能继承一个抽象类
6)抽象类中可以定义成员变量

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

1) 没有构造方法,不能创建对象
20 接口中定义抽象方法时,无需加public abstract修饰符
3) 接口中可以存在被default或static修饰的方法
4) 接口被子类实现时,用implements关键字。子类需要重写父接口中的所有抽象方法
5) 子类可以实现多个接口,用逗号隔开
6) 接口中定义的属性都是公共的静态常量,被public static final修饰,必须要有初始值

相同点

1) 接口和抽象类都无法创建对象
2) 接口的实现类和抽象类的子类,都需要重写抽象方法
接口是一个完全抽象类。JDK1.8之后可以在接口中定义有方法体(被default或static修饰)的方法。

static静态的

  1.  每次new创建一个对象,都会在堆空间中开辟一块区域,这个过程是需要花费时间和空间的。
    
  2. 在栈空间中,只会定义变量,保存堆空间中某块区域的地址。通过变量访问堆空间中对应地址的数据。
  3.  如果多个对象都有相同的属性或方法时,可以将这些公共的属性和方法使用static修饰,
    
  4.  让其成为静态数据,在类加载的时候就保存在静态区中
    

在不使用静态成员时

在这里插入图片描述
如上图的"重庆大学"这个字符串,每个对象都会使用,就可以将其使用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);
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值