java学习 day05 面向对象(上)----类和对象

130 阅读6分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第十四天,点击查看活动详情

总概:面向对象

面向对象三条主线:

1.java类及类的成员,属性 方法 构造器 代码块 内部类

2.面向对象的三大特征:封装 继承 多态 (抽象性)

3.其他关键字:this super static final abstract
interface package import

相关面试题

image.png

image.png

画出下面代码在执行时的内存分配情况

image.png

类和对象

image.png

image.png

image.png

image.png 创建是指通过new创建

jvm内存结构与对象的内存解析

jvm内存结构

编译完源程序以后,生成一个或多个字节码文件

我们使用JVM中的类的加载器和解释器对生成的字节码文件进行解释运行.意味着,需要将字节码文件对应的类加载到内存中,涉及到内存解析.

所以内存解析是在执行java XXX时才进行.

image.png 虚拟机栈,即我们平时提到的栈结构.我们将局部变量存储到栈结构中.

堆,我们将new出来的结构(如 数组 对象)加载到堆空间中.补充:对象的属性(非static的)加载到堆空间内.

方法区:类的加载信息 常量池 静态域.

注意:内存解析的说明

引用类型的变量,只能存储两种值:null或地址值(含变量的类型)

对象的内存解析

image.png

对象数组的内存解析

image.png

类的成员之一属性

(成员变量)VS局部变量

image.png

image.png 局部变量不可以使用权限修饰符

image.png

image.png

image.png

补充:变量的分类

image.png

image.png

类的成员之二方法

image.png

void表示没有返回值

image.png

image.png

image.png

方法应用

题目一

image.png


package com.atguigu.obj;

public class MethodTest {
	public static void main(String[] args){
		Print p1 = new Print();
		p1.length=10;
		p1.width=8;
		p1.print();
		
		PrintTwo p2 = new PrintTwo();
	System.out.println(p2.print(10,8));	
		
	}

}

class Print{
	int length;
	int width;
	
	public void print(){
		for(int i=0;i<width;i++){
			for(int j=0;j<length;j++){
				System.out.print("* ");
			}
			System.out.println();
		}
	}
}

class PrintTwo{	
	
	public int print(int m,int n){
		for(int i=0;i<m;i++){
			for(int j=0;j<n;j++){
				System.out.print("* ");
			}
			System.out.println();
		}
		return m*n;
	}
}
题目二

image.png

针对于第四题

package com.atguigu.obj;

public class ArryTest {
	public static void main(String[] args){
		//声明student类型的数组
		Student[] stu=new Student[20];
		for(int i=0;i<stu.length;i++){			
			//给数组元素赋值
			stu[i]=new Student();
			//给student对象的属性赋值
			stu[i].number=(i+1);
			//[1,6]
			stu[i].state=(int)(Math.random()*(6-1+1)+1);
			//[0-100]
			stu[i].score=(int)(Math.random()*(100-0+1)+0);
		}
		for(int i =0;i<stu.length;i++){   //打印一下所有学生的信息
			System.out.println(stu[i].getInfo());
		}
		
		
		for(int i =0;i<stu.length;i++){  //打印3年级学生的信息
			if(stu[i].state==3){
				System.out.println("dddddd");
				System.out.println(stu[i].getInfo());
			}
			
		}
		//使用冒泡排序按学生成绩排序,并遍历所有学生信息
		for(int i= 0;i<stu.length-1;i++){
			for(int j=0;j<stu.length-1-i;j++){
				//从小到大排序(冒泡)
				if(stu[j].score>stu[j+1].score){
					//交换的是数组中的对象 不能是成绩
					Student temp=stu[j];
					stu[j]=stu[j+1];
					stu[j+1]=temp;
					
					
				}
				
			}
			
		}
		System.out.println("*********");
		for(int i = 0;i<stu.length;i++){
			System.out.println(stu[i].getInfo());
		}
		
		
		
	}

}

class Student{
	int number;
	int state;
	int score;
	
	public String getInfo(){
		String info="学号"+number+",年级"+state+",成绩"+score;
		return info;
	}
}

对上述代码进行优化(暂未完成)

www.bilibili.com/video/BV1Qb…

return关键字

image.png

方法的重载(重点)

image.png

image.png

image.png

image.png

image.png

同一个类中,只要方法名相同,参数个数和参数类型不同即可构成重载. image.png

可变个数形参的方法

image.png 注意:上述标红的部分不能在一个类中共存

  1. jdk 5.0新增的内容

  2. 具体使用

  • 可变个数形参的格式: 数据类型...变量名
  • 当调用可变个数形参的方法时,传入的参数个数可以是0个,1个,2个...
  • 可变个数形参的方法与本类中的方法名相同,形参不同的方法之间构成重载
  • 必须声明在末尾

image.png

image.png

image.png

image.png

方法的参数传递----值传递机制

温习基础:变量赋值

image.png

方法形参的值传递机制:

image.png

思考下面为什么没有交换成功

www.bilibili.com/video/BV1Qb…



package com.atguigu.obj;

/**   
 * @ClassName:  Test
 * @Description:
 * @author:露
 * @date:2022年8月26日 上午10:21:37
 */

public class Test {
	public static void main(String[] args) {
		Test test = new Test();
		
		
		int a=1;
		int b=2;
//		int temp = a;
//		a=b;
//		b=temp;
		test.swap(a, b);
		System.out.println("a:"+a+" b:"+b); //第一种写法:a:2 b:1   第二种写法 a:1 b:2 (没有交换成功)
		
		
		
	}
	
	
	public void swap(int a,int b){
		int temp = a;
		a=b;
		b=temp;
	}
}

image.png 之所以没有实现m和n的交换,是因为swap方法执行完就销毁了,里面的变量也相应出栈.所以打印出来m,n的值没有变,还是main 方法一开始定义的值

此时 才能够交换成功



package com.atguigu.obj;

/**   
 * @ClassName:  Test2
 * @Description:
 * @author:露
 * @date:2022年8月26日 上午11:17:32
 */

public class Test2 {
	public static void main(String[] args) {
		Data data=new Data();
		data.a=1;
		data.b=2;
		System.out.println("a:"+data.a+" b:"+data.b);  //a:1 b:2
		//交换两个变量的值
//		int temp = data.a;
//		data.a=data.b;
//		data.b=temp;
//		System.out.println("a:"+data.a+" b:"+data.b);  //a:2 b:1
		
		//
		Test2 t2 = new Test2();
		t2.swap(data);
		System.out.println("a:"+data.a+" b:"+data.b);  //a:2 b:1(交换成功
		
	}
	public void swap(Data data){
		int temp = data.a;
		data.a=data.b;
		data.b=temp;
		
	}
	

}

class Data{
	int a;
	int b;
}

内存分析(为什么能交换成功)

image.png

同理来改一下这个

image.png

image.png

练习

第一题 image.png

image.png

第二题

image.png




package com.atguigu.exe4;

/**   
 * @ClassName:  PassObject
 * @Description:
 * @author:露
 * @date:2022年8月26日 下午12:13:07
 */

public class PassObject {
	public static void main(String[] args) {
		PassObject po=new PassObject();
		Circle c = new Circle();
		
		po.printAreas(c,5);
		System.out.println("now c的radius"+c.radius);  //now c的radius5.0
	}
	
	//Circle c是一个地址值
	public void printAreas(Circle c,int time){
		System.out.println("Radius\t\tArea");
		for(int i=1;i<=time;i++){
			
			c.radius=i;
			System.out.println(c.radius+"\t\t"+c.findArea());
		}
	}

}

方法:递归方法

image.png

image.png

考虑 一次只能跨1个或2个台阶,要跨完n个台阶,有多少种组合方法(这个可以参考上述7.3)

image.png

image.png

image.png

经典面试题

image.png

类的成员之三:构造器

构造器的作用:创建对象

通常我们都会给类提供一个空参的构造器

构造器与类同名

构造器的权限最大不能超过类的权限

image.png

image.png

image.png

image.png

image.png

image.png 多个构造器构成构造器的重载

属性赋值的先后顺序

image.png 前三个都可以叫做初始化 都只执行一次

image.png

this关键字

image.png

image.png

image.png

image.png

image.png

匿名对象

image.png

image.png

image.png

类的成员之四---代码块

image.png

package com.atguigu.java3;
/*
 * 类的成员之四:代码块(或初始化块)
 * 
 * 1. 代码块的作用:用来初始化类、对象
 * 2. 代码块如果有修饰的话,只能使用static.
 * 3. 分类:静态代码块  vs 非静态代码块
 * 
 * 4. 静态代码块
 * 	   >内部可以有输出语句
 * 	   >随着类的加载而执行,而且只执行一次
 * 	   >作用:初始化类的信息
 * 	   >如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
 * 	   >静态代码块的执行要优先于非静态代码块的执行
 * 	   >静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
 * 
 * 5. 非静态代码块
 * 		>内部可以有输出语句
 * 		>随着对象的创建而执行
 * 		>每创建一个对象,就执行一次非静态代码块
 * 		>作用:可以在创建对象时,对对象的属性等进行初始化
 * 		>如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
 * 		>非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
 * 
 */
public class BlockTest {
	public static void main(String[] args) {
		
		String desc = Person.desc;
		System.out.println(desc);
		
		Person p1 = new Person();
		Person p2 = new Person();
		System.out.println(p1.age);
		
		Person.info();
	}
}


class Person{
	//属性
	String name;
	
	int age;

	static String desc = "我是一个人";
	
	//构造器
	public Person(){
		
	}
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	//非static的代码块
	{
		System.out.println("hello, block - 2");
	}
	{
		System.out.println("hello, block - 1");
		//可以调用非静态结构
		age = 1;
		eat();
		//也调用静态结构
		desc = "我是一个爱学习的人1";
		info();
	}
	//static的代码块
	static{
		System.out.println("hello,static block-2");
	}
	static{
		System.out.println("hello,static block-1");
		//只能调用静态结构
		desc = "我是一个爱学习的人";
		info();
		//不可以调用非静态结构
//		eat();
//		name = "Tom";
	}
	
	//方法
	public void eat(){
		System.out.println("吃饭");
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	public static void info(){
		System.out.println("我是一个快乐的人!");
	}
	
}

面向对象的三大特点

封装性

为什么要引入封装性

image.png

封装性的体现:

只要涉及到四种权限的都体现封装性

image.png

四种访问权限修饰符

:类 类的属性\构造器\方法等都可以使用权限修饰符

image.png

不同包的子类中子类是指有继承关系的.

例如

image.png

image.png

继承性

image.png

image.png

image.png

image.png

java.lang.Object类的理解

Object是所有类的父类,也称根父类 image.png image.png

image.png

方法的重写(重点)

image.png

image.png

image.png

image.png

image.png

image.png 注意:只有非static才有方法的重写,静态的方法不能被覆盖,是随着类的加载而加载的.

super关键字

image.png

image.png

image.png

super调用构造器

  • 可以在子类的构造器中显式的使用super(形参列表),调用父类中声明的指定构造器
  • super(形参列表)的使用,必须在子类构造器的首行
  • 在类的构造器中,this(形参列表)或super(形参列表)只能二选一,不能同时出现
  • 在构造器的首行,没有显示的声明this(形参列表)或super(形参列表),默认调用的是父类中的空参构造器.
  • 在类的多个构造器中,至少有一个类的构造器中使用了super(形参列表),调用父类中的构造器

image.png

image.png

image.png

注意

image.png

子类对象的实例化过程

image.png

image.png

image.png

image.png

多态性

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

注意:为什么说方法调用在编译期间是无法确定的

image.png

image.png

image.png image.png

总结:多态性是运行时的行为

相关面试题

image.png

image.png

image.png 第二个红框是多态性

注意

image.png

向下转型

Person p = new Man( ); //正确

Man m = p //错误 把父类对象转换为子类对象 就是向下转型 要使用强制 类型转换符 ,如下:

Man m = (Man)p

image.png

image.png

instanceof操作符

前提回顾:Person p2 = new Man( )

image.png

image.png 技巧1:new的谁,肯定是谁的类型(实例)

比如:Person p = new Man( )

p instance of Man 的结果是true

重要结论

关键看:1是不是2的实例(往往1是什么还要看它创建的时候new的谁) 如果1 instanceof 2 结果是true,则可以进行强转(编译和运行都通过)

image.png

image.png 强转----内存解析

image.png

image.png

多态性的使用体现

体现一 (下面都在一个文件里写的) image.png

image.png

image.png

体现二

image.png

体现三 image.png

image.png

多态性的练习

image.png



package com.atguigu.duotai;



public class IntanceTest {
	public static void main(String[] args) {
		IntanceTest ts = new IntanceTest();
		ts.method(new Student());
	}
	
	public void method(Person e){
	String info=e.getInfo();
	System.out.println(info);
	
	if(e instanceof Graduate){
		System.out.println("研究生  学生  人");
	}else if(e instanceof Student){
		System.out.println("学生 人");
	}else{
		System.out.println("人");
	}
	}

}

class Person {
	protected String name="person";
	protected int age = 50;
	public String getInfo(){
		return "Name:"+name+"\n"+"age:"+age;
	}
}

class Student extends Person{
	protected String school = "pku";
	public String getInfo(){
		return "Name:"+name+"\n age"+age+"\n school:"+school;
	}
}

class Graduate extends Student {
	public String major ="IT";
	public String getInfo(){
		return "Name:"+name+"\nage"+age+"\nschool:"+school+"\nmajor"+major;
	}
}

image.png

//多态性

package com.atguigu.duotai;



public class Instance {
	public static void main(String[] args) {
		Instance is = new Instance();
	Boolean	isTrue=is.equalsArea(new Circle("blue",34.0,23),new MyRectangle("red",34.5,23.3,33.3));
	System.out.println(isTrue);      //false
		is.displayGeometricObject(new Circle("blue",34.0,23));  //1661.9025137490005
	}
	
	public Boolean equalsArea(GeometricObject o1,GeometricObject o2){
		return (o1.findArea()==o2.findArea())?true:false;
		//return o1.findArea()==o2.findArea();
		
		
	}
	
	public void displayGeometricObject(GeometricObject o){
		System.out.println(o.findArea()); 
	}

}
class GeometricObject{
	protected String color;
	protected double weight;
	
	public GeometricObject(String color,double weight){
		this.color = color;
		this.weight=weight;
		
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public double getWeight() {
		return weight;
	}

	public void setWeight(double weight) {
		this.weight = weight;
	}
	
	public double findArea(){
		return 0.0;
		
	}
}
class Circle extends GeometricObject {
	private double radius;
	
	public Circle(String color,double weight,double radius){
		super(color,weight);
		this.radius=radius;
	}

	public double getRadius() {
		return radius;
	}

	public void setRadius(double radius) {
		this.radius = radius;
	}
	
	public double findArea(){
		return Math.PI*radius*radius;
	}
	
}
class MyRectangle extends GeometricObject{
	private double width;
	private double height;
	public MyRectangle(String color, double weight, double width, double height) {
		super(color, weight);
		this.width = width;
		this.height = height;
	}
	public double getWidth() {
		return width;
	}
	public void setWidth(double width) {
		this.width = width;
	}
	public double getHeight() {
		return height;
	}
	public void setHeight(double height) {
		this.height = height;
	}
	public double findArea(){
		return width*height;
	}
	
}

重点笔试题

package com.atguigu.exer;

//考查多态的笔试题目:
public class InterviewTest1 {

	public static void main(String[] args) {
		Base1 base = new Sub1();
		base.add(1, 2, 3);  //sub_1                
                

		Sub1 s = (Sub1)base;  //强转之后可以调用子类独有方法
		s.add(1,2,3);  //sub_2  //根据参数序列对应
                
                
	}
}

class Base1 {
	public void add(int a, int... arr) {
		System.out.println("base1");
	}
}

class Sub1 extends Base1 {

	public void add(int a, int[] arr) {  //重写了父类同名方法
		System.out.println("sub_1");  
	}

	public void add(int a, int b, int c) { 
		System.out.println("sub_2");
	}

}