1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)

生活角度面向对象:找合适的人做合适的事

生活角度面向过程:亲历亲为,自力更生

类和对象

对象
电脑类 我的机械革命
汽车类 1949红旗
人类 乔布斯,比尔盖茨,马化腾

类:对于一类事物的统称,对当前事务的一些描述,属性描述和行为描述

对象:独立,唯一,特殊的个体

Java中定义类的格式

class ClassName{
     
    // 属性描述
    // 行为描述
}

要求:

  1. ClassName 使用大驼峰命名法,见名知意
  2. 属性描述,是用于描述当前类拥有的一些特性,可以使用变量,称为成员变量 Field
  3. 行为描述,用于描述当前类可以做的一些事情,可以使用方法,称为成员方法 Method

定义成员变量

class Person {
     
	// 使用String类型描述Person类的姓名属性
	String name;
	// 使用int类型描述Person类的年龄属性
	int age;
	// 使用char类型数据描述Person类的性别属性
	char gender;
}

定义成员方法

class Person {
     
	// 使用方法描述Person类的吃饭行为
	public void eat(String food) {
     
		System.out.println("吃" + food);
	}
	// 使用方法描述Person类的睡觉行为
	public void sleep() {
     
		System.out.println("睡觉了");
	}
	// 使用方法描述Person类的打豆豆行为
	public void daDOUDOU() {
     
		System.out.println("吃饭睡觉打豆豆");
	}
}

eclipse快捷键

force模式:ctrl + shift + a 再按一遍切回

类对象使用

创建(new)对象

类名 对象名 = new 构造方法(所需参数);

// 例:获取一个扫描器对象
// 需要先导包 
import java.util.Scanner;

Scanner sc = new Scanner(System.in);
/* 
数据类型:
	Scanner类型,创建的变量是Scanner的类对象,同时也是一个引用数据类型

sc:
	类对象,变量
	Scanner的类对象,sc是对象名
	
new:
	申请内存的 堆区 空间,并且清理整个空间中的所有数据
	代码中,只要在有new关键字时,一定会用到内存的堆区空间,并且时新的内存空间
	
Scanner(System.in):
	这是一个方法,因为有小括号,没有小括号就是变量
	方法名字和类名一致
	该方法被称为构造方法,Constructor构造方法
*/

新建两个对象

package cn.ocean888;

class Person {
     
	// 使用String类型描述Person类的姓名属性
	String name;
	// 使用int类型描述Person类的年龄属性
	int age;
	// 使用char类型数据描述Person类的性别属性
	char gender;
}

public class Demo1 {
     
	public static void main(String[] args) {
     
		Person ocean = new Person();
		System.out.println(ocean);
		
		Person ocean2 = new Person();
		System.out.println(ocean2);
	}
}

输出结果

image-20210508114922425

  • cn.ocean888 是完整的包名
  • Person 数据类型
  • @15db9742 是当前类对象在内存空间中的首地址,十六进制格式
  • 两个对象的首地址不一致,说明这不是一个对象

调用类成员变量

通过Person类对象,调用类内的成员变量

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第1张图片

public class Demo1 {
     
	public static void main(String[] args) {
     
		Person ocean = new Person();
		// 赋值
		ocean.name = "ocean";
		ocean.age = 18;
		ocean.gender = '男';
		
		// 取值
		System.out.println("name : " + ocean.name);
		System.out.println("age : " + ocean.age);
		System.out.println("gender :" + ocean.gender);
	}
}

image-20210508120358458

调用类成员方法

类对象.方法名(参数);
package cn.ocean888;

/**
 * 
 * @author q2723
 *
 */
class Person {
     	
	// 使用方法描述Person类的吃饭行为
	public void eat(String food) {
     
		System.out.println("吃" + food);
	}
	// 使用方法描述Person类的睡觉行为
	public void sleep() {
     
		System.out.println("睡觉了");
	}
	// 使用方法描述Person类的打豆豆行为
	public void daDOUDOU() {
     
		System.out.println("吃饭睡觉打豆豆");
	}
}

public class Demo1 {
     
	public static void main(String[] args) {
     
		Person ocean = new Person();
		// 调用类内的eat方法,注意eat有参则需要传入参数
		ocean.eat("bread");
		ocean.sleep();
		ocean.daDOUDOU();
	}
}

image-20210508120858946

内存中的对象

类对象内存分析

对象也是引用传参

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第2张图片

注意:char的默认值为 ‘\0’ null

类对象地址转移

类对象和数组类似,都是引用传参,栈区存储的是首地址

dog1=dog2,就是把dog2首地址给dog1,此时dog1和dog2都指向原dog2的内存空间,原dog1的空间变为无主空间被释放

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第3张图片

构造方法

反编译class文件

找到字节码文件看反编译结果

1.eclipse会自动把.class字节码文件放到指定文件夹

项目名上右击,选择properties

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第4张图片

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第5张图片

字节码文件在bin目录下

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第6张图片

2.在此文件夹打开终端

3.反编译字节码文件命令

Javap -c -l -private .\Person.class

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第7张图片

通过反编译工具,发现一些不存在于原来代码中的内容,这些内容是Java编译器为了方便程序开发,提供的必要的无参数构造方法

Java编译器如果发现当前class没有显式自定义构造方法,回默认提供一个无参数构造方法给予使用

如果java编译器发现代码中存在构造方法,java编译器则不会提供无参构造方法

自定义使用构造方法

构造方法功能:

​ 初始化当前类对象中保存的成员变量数据

new和构造方法作用:

  • new

    1.根据构造方法提供的数据类型申请对应的堆区内存空间

    2.查出整个空间中所有的数据

  • 构造方法

    初始化在当前内存堆区空间的成员变量对应的数据

构造方法的书写格式:

public 类名(初始化形式参数列表) {
     
    初始化赋值语句;
}

例1:

并没有构造方法,所以Java编译器将提供默认构造方法Cat

package cn.ocean888;

import java.util.Locale.Category;

class Cat {
     
	String name;
    // 并没有构造方法,所以Java编译器将提供默认构造方法Cat
}

public class Demo2 {
     
	public static void main(String[] args) {
     
		// 新建一个cat类
		Cat cat = new Cat();
		cat.name = "huahua";
		System.out.println(cat.name);
	}
}

image-20210508143016270

例2:

有无参构造方法,Java编译器不再提供默认构造方法

package cn.ocean888;

import java.util.Locale.Category;

class Cat {
     
	String name;
	public Cat() {
     
		System.out.println("this is constructor");
	}
}

public class Demo2 {
     
	public static void main(String[] args) {
     
		// 新建一个cat类
		Cat cat = new Cat();
		cat.name = "huahua";
		System.out.println(cat.name);
	}
}

image-20210508142954109

例3:

存在有参构造方法,不存在无参构造方法的情况

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第8张图片

因为此时java编译器发现代码中存在构造方法,java编译器则不会提供无参构造方法,所以箭头指向位置会报错,需要开发者自己写无参构造方法

package cn.ocean888;

import java.util.Locale.Category;

class Cat {
     
	String name;
	// 无参方法
	public Cat() {
     
		System.out.println("this is a constructor whitout parameter");
	}
	
	// 有参方法
	public Cat(int age) {
     
		System.out.println("age:" + age);
	}
	
}

public class Demo2 {
     
	public static void main(String[] args) {
     
		// 新建一个cat对象
		Cat cat = new Cat();
		// 新建一个有参对象
		Cat cat2 = new Cat(2);
		cat.name = "huahua";
		System.out.println(cat.name);
	}
}

image-20210508143522784

例4:

带有两个参数的构造方法

package cn.ocean888;

import java.util.Locale.Category;

class Cat {
     
	String name;
	int age;
	// 无参方法
	public Cat() {
     
		System.out.println("this is a constructor whitout parameter");
	}
	
	// 有参方法
	public Cat(int age) {
     
		System.out.println("age:" + age);
	}
	
	// 两个参数的有参方法
	public Cat(int age, String name) {
     
		name = name;
		age = age;
		System.out.println("有一只" + age + "岁的" + name);
	}
}

public class Demo2 {
     
	public static void main(String[] args) {
     
		// 新建一个cat对象
		Cat cat = new Cat();
		// 新建一个有参对象
		Cat cat2 = new Cat(2);
		cat.name = "huahua";
		System.out.println(cat.name);
		
		// 新建一个两个参数的有参对象
		Cat cat3 = new Cat( 5, "加菲猫");
	}
}

image-20210508150755730

总结:

  1. 无论何时类里要有一个无参数构造方法
  2. 根据所需情况完成构造方法参数选择
  3. 一个class可以有多个构造方法(方法的重载)

方法重载

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第9张图片

这四个方法特点总结:

  1. 所有方法名字都是一致的
  2. 所有方法参数都不一样
  3. 同一个类内

tips:C语言不允许方法名重复

这就是方法重载

规范:

​ 重载情况下,在同一个类内,不可以出现相同方法名和相同参数数据的方法存在的,只能有一个

原理:

方法名一致的情况下,通过形式参数列表数据类型的不同来选择不同的方法执行

this关键字

就近原则

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第10张图片

在构造方法中age,name因为就近原则,会被看做是一个局部变量

此时就应该使用this关键字

this

package cn.ocean888;

class Dog {
     
	public Dog() {
     
		System.out.println("address : " + this);
	}
}

public class Demo3 {
     
	public static void main(String[] args) {
     
		Dog dog = new Dog();
		System.out.println("address : " + dog);
	}
}

image-20210508155752077

在输出中可以看出来 this 的就是对象首地址,this 指的就是对象本身

这样的话之前就近原则的问题就可以解决了

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第11张图片

this.name就是成员变量,而name是局部变量

成员变量和局部变量的对比

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第12张图片

补充

零值

new 关键字申请内存空间时,会擦出数据,填入零值

基本数据类型对应的零值

byte short int		 0
long				0L
float				0.0F
double				0.0
char				'\0' => ascii nul
boolean				false

引用数据类型对应的零值

全部为 null
例:
Person				null
String str			 null
int[] arr			 null

JVM-GC垃圾回收

GC(Garbage Collection)

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第13张图片

java中内存管理机制就类似于图书管理员身份

  1. 在单位时间内,检查当前Java程序使用的内存是否存在无主内存
  2. 标记无主内存,多次标记的情况下,会将无主内存内存释放,归还内存空间

优点:

  1. 程序员管理内存更加方便
  2. 内存管理完全自动化

缺点:

  1. 内存回收效率不高
  2. 内存管理出现泄露问题

二分查找

特征:

  • 要求查询的数组必须是一个经过排序之后的数组
  • 查询出多个指定的数据的情况下,无法告知到底是第几个数据出现
  • 没有找到数据返回负数
public class Demo4 {
     
	public static void main(String[] args) {
     
		int[] sortedArray = {
     1,3,5,6,7,8,9,10,11,23};
		int find = 3;
		int result = 0;
		result = halfSearch(sortedArray, find);
		System.out.println(result);
	}
	
	/**
	 * 二分查找
	 * @param sortedArray 要找的数组,数组必须有序 
	 * @param find 在数组中查找的数据
	 * @return 以数字形式返回查找结果,-1表示没有找到,数字表示查找数据所在的位置
	 */
	public static int halfSearch(int[] sortedArray, int find) {
     
		int minIndex = 0;
		int maxIndex = sortedArray.length;
		int midIndex = (minIndex + maxIndex) / 2;
		while (minIndex <= maxIndex ) {
     
			if (sortedArray[midIndex] > find ) {
     
				maxIndex = midIndex - 1;
			} else if (sortedArray[midIndex] < find) {
     
				minIndex = midIndex + 1;
			} else {
     
				return midIndex;
			}
			midIndex = (minIndex + maxIndex) / 2;
		}
		return -1;
	}
}
em.out.println(result);
	}
	
	/**
	 * 二分查找
	 * @param sortedArray 要找的数组,数组必须有序 
	 * @param find 在数组中查找的数据
	 * @return 以数字形式返回查找结果,-1表示没有找到,数字表示查找数据所在的位置
	 */
	public static int halfSearch(int[] sortedArray, int find) {
     
		int minIndex = 0;
		int maxIndex = sortedArray.length;
		int midIndex = (minIndex + maxIndex) / 2;
		while (minIndex <= maxIndex ) {
     
			if (sortedArray[midIndex] > find ) {
     
				maxIndex = midIndex - 1;
			} else if (sortedArray[midIndex] < find) {
     
				maxIndex = midIndex + 1;
			} else {
     
				return midIndex;
			}
			midIndex = (minIndex + maxIndex) / 2;
		}
		return -1;
	}
}

封装

面向对象三大特征

封装,继承,多态

封装是一个概念,不局限于面向对象的封装

  • 方法的封装
  • 工具类的封装
  • 框架的封装

符合JavaBean规范的类封装过程

要求:

  1. 所有的成员变量全部私有化 ==> private
  2. 必须提供一个无参构造方法
  3. 使用private修饰的成员变量提供对应的操作方法 ==> Setter Getter

private关键字

private关键字是一个权限修饰符

private修饰的成员变量,成员方法,构造方法都是私有化内容,有且只能在类内使用,类外没有任何的操作权限

image-20210509102626700

私有方法不能访问

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第14张图片

借助eclipse的outline窗口也可以看到属性和方法的类型

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第15张图片

Setter和Getter方法

private修饰的成员变量类外是没有任何操作权限,这里需要提供对应的操作方法,setter和getter方法

Setter方法格式:

public void set成员变量名(对应成员变量的数据类型 成员变量的形式参数) {
     
	this.成员变量 = 成员变量的形式参数;
}

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

Getter方法格式:

public 对应成员变量的数据类型 get成员变量名() {
     
    return 成员变量;
}

例如:
public String getName() {
     
    return name;
}

tips:

boolean 类型格式规范

例:

// 定义格式
boolean married;

// getter格式
public boolean isMarried() {
     
    return married;
}

其余数据类型都是getName,setName

自动生成Constructor,Setter,Getter

ctrl + alt + s

  • 生成无参和有参构造方法

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第16张图片

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第17张图片

  • 生成Getter和Setter

ctrl + alt + s

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第18张图片

select all

tips:使用时简写eclipse会自动补齐

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第19张图片

生成效果

package com.ocean888;

class Cat {
     
	
	String name;
	int age;
	char gender;
	boolean married;
	
	// 根据实际需要完成对应Constructor,Setter,Getter
	public Cat() {
     
		super();
	}


	
	public Cat(String name, int age, char gender, boolean married) {
     
		super();
		this.name = name;
		this.age = age;
		this.gender = gender;
		this.married = married;
	}



	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 char getGender() {
     
		return gender;
	}



	public void setGender(char gender) {
     
		this.gender = gender;
	}



	public boolean isMarried() {
     
		return married;
	}



	public void setMarried(boolean married) {
     
		this.married = married;
	}
	
}

public class Demo7 {
     
	public static void main(String[] args) {
     
		Cat cat = new Cat();
		
		cat.setName("xiaohua");
		cat.setAge(2);
		cat.setGender('雄');
		cat.setMarried(false);
		
		System.out.println("name:" + cat.getName());
		System.out.println("age:" + cat.getAge());
		System.out.println("gender:" + cat.getGender());
		System.out.println("married:" + cat.isMarried());
	}
}

image-20210509110528502

多类合作

电脑组装案例

开发中更多的情况需要多类合作完成,以电脑组装为例,

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第20张图片

Demo.java

package com.ocean888;

public class Demo1 {
     
	/*
	 * 主函数
	 */
	public static void main(String[] args) throws InterruptedException {
     
		// 新建一个computer对象
		Computer computer = new Computer(true);
		for (int i = 0; i < 10; i++) {
     
			computer.coumputerRunning();
			Thread.sleep(500);
		}
		
		computer.setScrennShow(false);
		computer.coumputerRunning();


		Factory factory = new Factory();
		factory.setName("ocean's 小店");
		factory.setAddr("北京二仙桥");
		factory.setTele(11111111);
		
		factory.repair(computer);
		
		for (int i = 0; i < 10; i++) {
     
			computer.coumputerRunning();
			Thread.sleep(500);
		}
	}
}

Computer.java

package com.ocean888;

public class Computer {
     
	// 成员变量屏幕是否显示
	private boolean isScrennShow;

	
	
	public Computer() {
     
		super();
	}


	public Computer(boolean isScrennShow) {
     
		super();
		this.isScrennShow = isScrennShow;
	}


	public boolean isScrennShow() {
     
		return isScrennShow;
	}


	public void setScrennShow(boolean isScrennShow) {
     
		this.isScrennShow = isScrennShow;
	}
	
	/*
	 * 屏幕显示情况判断
	 */
	public void coumputerRunning() {
     
		if (isScrennShow) {
     
			System.out.println("屏幕显示正常,尽情玩耍吧");
		} else {
     
			System.out.println("屏幕显示异常,需要维修!");
		}
	}
}

Factory.java

package com.ocean888;

public class Factory {
     
	private String name;
	private String addr;
	private int tele;
	
	
	
	public Factory() {
     
		super();
	}



	public Factory(String name, String addr, int tele) {
     
		super();
		this.name = name;
		this.addr = addr;
		this.tele = tele;
	}



	public String getName() {
     
		return name;
	}



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



	public String getAddr() {
     
		return addr;
	}



	public void setAddr(String addr) {
     
		this.addr = addr;
	}



	public int getTele() {
     
		return tele;
	}



	public void setTele(int tele) {
     
		this.tele = tele;
	}



	public void repair(Computer computer) throws InterruptedException {
     
		if(!computer.isScrennShow()) {
     
			System.out.println("您的电脑已送达" + this.name + ",地址:" + this.addr +",联系电话:" + this.tele);
			System.out.println("电脑修理中~~~");
			Thread.sleep(1000);

			computer.setScrennShow(true);
			System.out.println("修理完成");
		} else {
     
			System.out.println("检测完毕,电脑没有异常");
		}
	}
}

tips:Thread.sleep快速修复

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第21张图片

匿名对象

使用:

new 构造方法(参数);

用途:

  1. 使用匿名对象直接调用类内的成员变量
  2. 匿名对象直接作为方法的参数

注意:

使用匿名对象不要操作成员变量,有去无回

优点:

  1. 阅后即焚,匿名对象在使用之后,立即被JVM GC收回
  2. 解决了内存空间,提高效率,简化代码书写
package org.ocean888_a;

class Person {
     
	String name;
	int age;
}

public class Demo1 {
     
	public static void main(String[] args) {
     
		// new一个对象
		Person person = new Person();
		person.name = "ocean";
		System.out.println(person.name);
		// 输出地址
		System.out.println(person);
		
		// new一个匿名对象
		new Person().name = "ocean";
		System.out.println(new Person().name);
		// 输出地址
		System.out.println(new Person());
	}
}

image-20210510134557995

可以看出来匿名对象的地址和普通对象地址不一样,匿名函数尽在创建时有效,所以name=null

继承

继承使用

Java中的继承是单继承,一个子类只能拥有一个父类,所以 extends 只能继承一个类,所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类

继承使用的关键字
    extends
格式:
	class A extends B {
     
        
    }

A是B类的一个子类
B是A类的唯一父类    

基本要求:

  1. 子类继承父类后,可以使用父类的非私有化成员变量和成员方法
  2. 子类不能继承父类的私有化内容
package org.ocean888_a;

class Father {
     
	// 公共属性
	public String name;
	// 私有属性
	private double salary;
	
	// 无参构造
	public Father() {
     
		super();
	}
	
	// 有参构造
	public Father(String name, double salary) {
     
		super();
		this.name = name;
		this.salary = salary;
	}
	

	// 公共方法
	public void game() {
     
		System.out.println("捕鱼达人");
	}
	
	// 私有方法
	private void testPrivate() {
     
		System.out.println("父类私有方法");
	}
	
}

class Son extends Father {
     
	String name;
	int age;
	
	// 无参构造	
	public Son() {
     
		super();
	}
	
	// 有参构造	
	public Son(String name, double salary, String name2, int age) {
     
		super(name, salary);
		name = name2;
		this.age = age;
	}
	
	public void work() {
     
		System.out.println("就是玩");
	}
}

public class Demo2 {
     
	public static void main(String[] args) {
     
		Father father = new Father();
		father.name = "小头爸爸";
		father.game();
		
		Son son = new Son();
		son.age = 12;
		son.work();
		
		son.name = "大头儿子";
		son.game();
	}
}

执行结果

image-20210510150157616

继承父类和子类内存分析图

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第22张图片

super关键字

  1. 调用父类成员方法和成员变量的关键字
  2. 用于显式调用父类的构造方法

子类使用父类成员变量和成员方法

package org.ocean888_a;

class Animal {
     
	public String name = "动物";
	public void eat() {
     
		System.out.println("父类的eat方法");
	}
}

class Dog extends Animal {
     
	public String name = "狗";
	public void eat() {
     
		System.out.println("子类的eat方法");
	}
	
	public void test() {
     
		// 就近原则
		System.out.println(name);
		// 使用父类的name属性
		System.out.println(super.name);
		
		// 就近原则
		eat();
		// 使用父类的eat方法
		super.eat();
	}
}

public class Demo3 {
     
	public static void main(String[] args) {
     
		Dog dog = new Dog();
		dog.test();
	}
}

image-20210510151245834

super()调用父类的构造方法

super(实际参数)

Java编译器会根据实际参数的数据类型,参数顺序,选择对应的父类构造方法执行,初始化父类的成员空间,方法重载机制

package org.ocean888_a;

class Animal {
     
	String name;
	int age;
	
	public Animal() {
     
		System.out.println("父类构造方法");
	}
	
	public Animal(String name) {
     
		this.name = "huahua";
		System.out.println("单参数构造方法");
	}
	
	public Animal(String name, int age) {
     
		this.name = "huahua";
		this.age = 1;
		System.out.println("双参数构造方法");
	}
}

class Cat extends Animal {
     
	public Cat() {
     
		/*
		 * Constructor call must be the first statement in a constructor
		 * 必须在第一行,即只能有一个super()
		 */
		super();
	}
}

public class Demo4 {
     
	public static void main(String[] args) {
     
		Cat cat = new Cat();
	}
}

程序输出

image-20210510153614249

特点:

  1. 如果没有显式调用父类的构造方法,默认Java编译器会调用父类无参构造方法
  2. 根据数据类型选择对应方法
  3. super调用构造方法,必须在当前构造方法的第一行

方法重写

子类可以通过继承的方法获取父类中非私有化方法,但是父类的方法,不一定满足子类的情况

方法的重写就是解决在开发过程中,父类的方法不适用于子类的情况,子类可以重写父类的方法,完成自定义方法的使用

重写之后,在没有增加新的方法名的情况下,重写方法体内容,让方法满足子类,降低了开发压力

子类方法重写

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第23张图片

按回车

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第24张图片

package org.ocean888_a;

class Father {
     
	// 公共属性
	public String name;
	
	// 无参构造
	public Father() {
     
	}
	
	// 公共方法
	public void game() {
     
		System.out.println("捕鱼达人");
	}
	
	public void work() {
     
		System.out.println("工人");
	}
}

class Son extends Father {
     
	/*
	 * @Override 注解
	 * 开启重写严格格式检查
	 */
	@Override
	public void game() {
     
		System.out.println("LOL");
	}
	@Override
	public void work() {
     
		System.out.println("学生");
	}
} 

public class Demo2 {
     
	public static void main(String[] args) {
     

		Son son = new Son();
		son.work();
		son.game();
	}
}

执行结果

image-20210510171639276

abstract关键字

abstract修饰的方法:要求子类强制重写

先贴一个例子

package org.ocean888_b;

abstract class LOLHero {
     
	abstract public void Q();
	
	abstract public void W();
	
	abstract public void E();
	
	abstract public void R();
}

/*
 * 子类继承父类可以直接使用父类的方法,但是这种情况下
 * 父类的方法不能在子类中使用
 */
class VN extends LOLHero {
     

	@Override
	public void Q() {
     
		System.out.println("斩刚闪");
	}

	@Override
	public void W() {
     
		System.out.println("致命打击");		
	}

	@Override
	public void E() {
     
		System.out.println("审判");		
	}

	@Override
	public void R() {
     
		System.out.println("德玛西亚");		
	}
}

public class Demo1 {
     
	public static void main(String[] args) {
     
		VN vn = new VN();
		vn.Q();
		vn.W();
		vn.E();
		vn.R();
	}
}

image-20210511221712034

  1. abstract修饰的方法没有方法体

  2. abstract修饰的方法必须定义在abstract修饰的类内或者interface接口内

  3. 一个普通类【非abstract】修饰的类,继承了一个abstract类,强制要求必须实现在abstract类内的所有abstract方法,做到多类规范

  4. 如果一个abstract A类继承另一个abstract B类,A类可以选择B类中abstract方法

  5. abstract修饰的类内允许普通方法

  6. abstract修饰的类不能创建自己的类对象,不能实例化,只能被继承

    原因:abstract修饰的类内可能存在abstract修饰的方法,而abstract修饰的方法是没有方法体的,如果说创建了abstract修饰类对应的对象,不能执行没有方法体的abstract方法

  7. 如果一个abstract类中没有abstract方法,那这个类是没有意义的

final关键字

package org.ocean888_b;

final class A {
     
	// final修饰成员变量name如果没有初始化会报错
	// The blank final field nameString may not have been initialized
	// 原因:final修饰的成员变量在定义时必须初始化
	public final String nameString = "ocean";
	
	// final关键字修饰的方法不能被子类重写
	public final void testA() {
     
		System.out.println();
	}
	
	
}

// final修饰类
// final class A {
     
// The type B cannot subclass the final class A
class B extends A {
     
	// 重写A类中的testA方法报错
	// Cannot override the final method from A
	// 原因:不能重写final关键字修饰的方法
	@Override
	public void testA() {
     
		System.out.println("重写");
	}
}
public class Demo2 {
     
	public static void main(String[] args) {
     
		// final修饰的局部变量
		final int num = 10;
		num = 20;
		// num = 20;报错The final local variable num cannot be assigned. It must be blank and not using a compound assignment
		// 原因:final修饰的局部变量一旦被赋值,无法进行修改
	}
}
  • final修饰的成员变量

    final修饰的成员变量在定义时必须初始化.并且赋值之后无法修改,一般用于类内带有名字的常量使用

  • final修饰的成员方法

    子类不能重写final关键字修饰的方法,为最终方法,可以用于一些安全性方法的定义

  • final修饰的局部变量

    final修饰的局部变量一旦被赋值,无法进行修改

  • final修饰的类

    final修饰的类为最终类,没有子类,不能被继承

    abstract修饰的类不能被final修饰

static关键字

static关键字的作用是:方便在没有创建对象的情况下调用方法/变量

static修饰成员变量

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第25张图片

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第26张图片

package org.ocean888_b;

class SingleDog {
     
	
	// static 修饰的静态成员变量
	public static String info = "单身狗";
	
	// 非静态成员便量
	public String name;

	public SingleDog() {
     }
	
	public SingleDog(String name) {
     
		this.name = name;
	}
	
	public void test() {
     
		System.out.println("test方法");
	}

}

public class Demo3 {
     
	public static void main(String[] args) {
     
		// 在没有对象的情况下,可以直接通过类名调用静态变量
		System.out.println(SingleDog.info);
		
		// 匿名对象,运行完毕,对象销毁
		new SingleDog();
		
		// 对象销毁之后,静态成员变量依然可以被调用
		System.out.println(SingleDog.info);
	}
}
  1. 静态成员变量使用static关键字修饰,定义在内存的“数据区”
  2. 静态成员变量不推荐使用类对象调用,会提示警告,使用static修饰的类成员变量,应该通过静态方式访问
  3. 静态成员变量使用类名调用是没有任何问题的
  4. 在代码中没有创建对象时,可以通过类名直接使用静态成员变量,和对象无关
  5. 对象销毁之后,静态成员变量依然可以被调用,和对象无关
  6. 修改静态成员变量的数据,所有使用到当前静态成员变量的位置,都会受到影响

静态成员变量和对象无关

  1. 从内存角度分析

    静态成员变量保存在内存的数据去

    类对象占用的实际内存空间是在内存的堆区

    两个区域不同

  2. 从生命周期分析

    静态变量是随着类文件(.class)字节码文件的加载过程中,直接定义在内存的数据区,静态成员变量从程序运行开始就已经存在

    类对象是在代码的运行过程中,有可能被创建的,成勋执行过程中,可能会被GC机制回收,程序在退出之前一定会销毁当前Java程序时用到的所有内存

    静态成员变量在程序退出之后,才会销毁

    静态成员变量的生命周期就是从程序开始到程序结束

    类对象只是在创建开始,而且有可能被GC回收

static修饰成员方法

静态成员方法的格式

public static 返回值类型 方法名 (形式参数列表) {
     
    
}
  1. 静态成员方法使用静态方式调用,即通过类名调用,不能使用类对象的方式调用,因为没有对象
  2. 静态成员方法中不能使用非静态成员
  3. 静态成员方法中不能使用this关键字
  4. 静态成员方法中可以使用类内的其他静态成员
  5. 静态成员方法中可以通过new构造方法创建对象

注:类方法中可以使用当前类内的静态成员变量,但不允许使用非静态成员变量

static修饰静态成员方法用途

  1. 摆脱类对象,效率高,节约内存空间,提高开发效率
  2. 类内成员变量和成员方法都不可以使用,但不影响使用外来数据
  3. 静态成员方法通常用于工具类的封装使用

例:自定义数组工具类

package org.ocean888_c;

import java.lang.reflect.Array;
import java.util.Arrays;

/**
 * 自定义数组工具类
 * 工具类中大多数方法,都是静态方法
 * @author q2723
 *
 */

class MyArrays {
     
	/**
	 * 数组工具类,数组逆序
	 * @param arr
	 */
	public static void reverse(int[] arr) {
     
		for (int i = 0; i < arr.length / 2; i++) {
     
			int temp = arr[i];
			arr[i] = arr[arr.length - 1 - i];
			arr[arr.length - 1 - i] = temp;
		}
	}
}


public class Demo1 {
     
	public static void main(String[] args) {
     
		int[] arr = {
     1,2,3,4,5,6,7,8};
		// 因为是static方法,所以不需要新建对象
		MyArrays.reverse(arr);
		System.out.println(Arrays.toString(arr));
	}
}

image-20210512205039443

三种代码块

  • 构造代码块
  • 静态代码块
  • 局部代码块

构造代码块

成员变量之后,构造方法之前

package org.ocean888_b;

class Dog {
     
	private String name;
	
	// 构造代码块,成员变量之后,构造方法之前
	{
     
		System.out.println("构造代码块");
	}
	
	// 无参构造
	public Dog() {
     
		System.out.println("无参构造");
	}
	
	// 有参构造
	public Dog(String name) {
     
		System.out.println("有参构造");
	}
}

public class Demo4 {
     
	public static void main(String[] args) {
     
		new Dog();
		new Dog("ocean");
	}
}

image-20210512165414708

局部代码块

提高效率,解决内存,提升jvm回收内存的效率

for() {
     
    
}

静态代码块

只要加载类文件,当前静态代码块中内容一定会执行,并且有且只执行一次

static {
     
    // 静态代码块
}
package org.ocean888_b;

class Cat {
     
	static {
     
		System.out.println("静态代码块");
	}
}

public class Demo5 {
     
	public static void main(String[] args) throws ClassNotFoundException {
     
		
		// 强制加载指定类,只会执行一次
		Class.forName("org.ocean888_b.Cat");
		Class.forName("org.ocean888_b.Cat");
		
		System.out.println("测试静态代码块");
	}
}

执行结果:

image-20210512193010554

静态代码块一边用于整个类的初始化

例题:

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第27张图片

执行效果:

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第28张图片

  1. 程序从上至下顺序执行,demo1对象生成时执行构造方法输出"构造方法块",触发Demo3无参方法输出"构造方法"
  2. demo2对象生成时执行构造方法输出"构造方法块",触发Demo3无参方法输出"构造方法"
  3. 加载静态方法
  4. 最后main方法中demo1触发构造方法

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第29张图片

例二:

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第30张图片

结果:程序进入死循环

原因:程序在第一行,new Demo3,Demo3类为本身,所以会出现递归情况,导致程序死循环

image-20210512195103783

编译不报错,运行报错

static修饰静态代码块

  1. static修饰的静态代码块,不能使用this关键字,不能使用类内的非静态成员
  2. static修饰的静态代码块,可以使用类内其他静态成员
  3. static修饰的静态代码块中,定义的变量都是局部变量,静态代码块,首先是一个代码块,拥有代码块的特征,其次才是用过static修饰之后,可以随着类文件的加载直接运行, 有且只运行一次

接口

格式

interface 接口名 {
     
    成员变量
    成员方法
}implements 接口 {
     
    
}
implements 可以理解为 遵从

例:

package org.ocean888_d;

interface A{
     
	// 缺省属性 public static final
	int num = 10;
	// 缺省属性public abstract
	void test();
}

/**
 * TypeA类遵从接口A
 * @author q2723
 *
 */
class TypeA implements A {
     
	@Override
	public void test() {
     
		System.out.println(num);
		System.out.println("接口");
	}
}
public class Demo1 {
     
	public static void main(String[] args) {
     
		TypeA typeA = new TypeA();
		typeA.test();
	}
}

image-20210513162741808

接口间继承

接口间可以继承,而且可以多继承

package org.ocean888_d;

interface B {
     
	// 缺省属性 public static final
	int numB = 10;
	// 缺省属性public abstract
	void testB();
}

interface C {
     
	// 缺省属性 public static final
	int numC = 20;
	// 缺省属性public abstract
	void testC();
}

interface D extends B,C {
     
	// 缺省属性 public static final
	int numD = 20;
	// 缺省属性public abstract
	void testD();
}

class TypeB implements D {
     
	@Override
	public void testB () {
     
		
	}
	
	@Override
	public void testC () {
     
		
	}
	
	@Override
	public void testD () {
     
		
	}
}

public class Demo2 {
     

}

默认方法

接口当中的默认方法

default方法,为接口提供了最基本的处理方法,非强制实现,可选

package org.ocean888_d;

interface F {
	// 接口当中的默认方法
	default void testF() {
		System.out.println("接口中默认方法");
	}
}

// 没有错误,因为接口中的方法是default方法 修饰,非强制实现
class TypeC implements F {
	
}

public class Demo3 {

}

总结

  1. 接口中成员变量缺省属性 public static final

    成员方法缺省属性 public abstract

  2. 一个非abstract类遵从interface接口,需要强制完成接口中所有缺省属性为public abstract的成员方法

  3. 接口与接口之间,允许使用extends关键字继承,允许一个,继承多个接口,就像生活中的向下兼容问题

  4. 接口中使用default关键字修饰方法,default方法拥有方法体,可以认为是非强制实现方法,不要求遵从接口的非abstract强制实现,jdk1.8新特性

接口实例:

生活中映射usb接口实例

鼠标类,键盘类

package org.ocean888_e;

import java.security.PublicKey;

interface USB {
     
	/*
	 * 要求所有的usb设备,必须完成的方法,告知usb接口连接之后完成的功能是什么
	 */
	
	void connect();
}

/*
 * 
 */
class Mouse implements USB {
     
	@Override
	public void connect() {
     
		System.out.println("鼠标链接usb接口,控制光标");
	}
}

/*
 * logi类继承于Mouse
 */
class Logi extends Mouse {
     
	@Override
	public void connect() {
     
		System.out.println("鼠标型号logi m275");
	}
}

class Keyboard implements USB {
     
	@Override
	public void connect() {
     
		System.out.println("键盘链接usb接口,控制键盘");
	}
}

class Ikbc extends Keyboard {
     
	@Override
	public void connect() {
     
		System.out.println("键盘型号ikbc w200");
	}
}

class PC{
     
	/*
	 * 电脑类连接usb接口连接方法
	 * @param usb
	 */
	
	public void usbConnect(USB usb) {
     
		// usb设备执行connect方法
		usb.connect();
	}
}

public class Demo1 {
     
	public static void main(String[] args) {
     
		PC pc = new PC();
		
		Mouse mouse = new Mouse();
		Logi logi = new Logi();
		Keyboard keyboard = new Keyboard();
		Ikbc ikbc = new Ikbc();
		
		pc.usbConnect(mouse);
		pc.usbConnect(logi);
		pc.usbConnect(keyboard);
		pc.usbConnect(ikbc);
	}
}

image-20210513175001335

这就是简单的多态

继承实例:

以动物园为例,所有的动物都可以看作一个Animal类,提供喂食方法,和获取动物名字的方法

package org.ocean888_e;

import javax.sound.midi.Soundbank;

class Animal {
     
	
}

/**
 * Dog类继承Animal类
 * @author q2723
 *
 */
class Dog extends Animal {
     
	
}

/**
 * Tiger类继承Animal类
 * @author q2723
 *
 */
class Tiger extends Animal {
     
	
}

/**
 * Panda类继承Animal类
 * @author q2723
 *
 */
class Panda extends Animal {
     

}

public class Demo2 {
     
	public static void main(String[] args) {
     
		Animal animal = new Animal();
		Dog dog = new Dog();
		Tiger tiger = new Tiger();
		Panda panda = new Panda();
		
		// 投喂动物
		feed(animal);
		feed(dog);
		feed(tiger);
		feed(panda);
		
		// 强制类型转换
		Dog dog2 = (Dog) getAnimal();
		System.out.println(dog2.getClass());
	}
	
	/**
	 * 投喂动物,获取动物对象
	 * @param animal
	 */
	public static void feed(Animal animal) {
     
		// 获取当前对象的完整包名.类名
		System.out.println(animal.getClass() + "来吃饭" );
	}
	
	/**
	 * 返回动物类对象
	 * @return
	 */
	public static Animal getAnimal() {
     
		return new Dog();
	}
}

1.2Java基础(二)面向对象(类和对象概念、封装、继承、多态)_第31张图片

多态

以上的两个案例其实就是多态的使用

  • 多态:父类的引用指向子类的对象或者说接口的引用指向遵从接口的类对象

作用:

  1. 扩宽方法的参数范围

    例如上边两个案例中

    方法参数为Animal类型

    可以传入Animal类型本身,或者传子类对象都可以

    public static void feed(Animal animal) {
           }
    
  2. 拓宽方法的返回值范围

  3. 简化代码开发,提高开发效率,整合数据类型

class Ikbc extends Keyboard {
     
	@Override
	public void connect() {
     
		System.out.println("键盘型号ikbc w200");
	}
}

class PC{
     
	/*
	 * 电脑类连接usb接口连接方法
	 * @param usb
	 */
	
	public void usbConnect(USB usb) {
     
		// usb设备执行connect方法
		usb.connect();
	}
}

public class Demo1 {
     
	public static void main(String[] args) {
     
		PC pc = new PC();
		
		Mouse mouse = new Mouse();
		Logi logi = new Logi();
		Keyboard keyboard = new Keyboard();
		Ikbc ikbc = new Ikbc();
		
		pc.usbConnect(mouse);
		pc.usbConnect(logi);
		pc.usbConnect(keyboard);
		pc.usbConnect(ikbc);
	}
}

这就是简单的多态

多态

以上的两个案例其实就是多态的使用

  • 多态:父类的引用指向子类的对象或者说接口的引用指向遵从接口的类对象

作用:

  1. 扩宽方法的参数范围

    例如上边两个案例中

    方法参数为Animal类型

    可以传入Animal类型本身,或者传子类对象都可以

    public static void feed(Animal animal) {
           }
    
  2. 拓宽方法的返回值范围

  3. 简化代码开发,提高开发效率,整合数据类型

多态的更多特征将会以实践案例的方式呈现.

你可能感兴趣的:(JAVA,java,编程语言,封装,面向对象编程)