面向对象-day04

面向对象-day04

今日学习内容:

  • this关键字
  • super关键字
  • static修饰符
  • final修饰符
  • 代码块
  • 内部类
  • 枚举

今日学习目标:

  • 重点掌握this关键字的含义和用法
  • 重点掌握super关键字的含义和用法
  • 掌握final修饰符的修饰类,方法,变量的含义
  • 了解代码块有那些
  • 掌握静态代码块的语法
  • 了解内部类有哪些
  • 掌握匿名内部类的语法
  • 掌握枚举类的定义和使用

13. 面向对象查漏补缺

13.1. this关键字(重点掌握)

什么是this:表示当前对象

this主要存在于两个位置:

  • 在构造器中:表示当前被创建的对象
  • 在 方法中:哪一个对象调用this所在的方法,此时this就表示哪一个对象
public class Cat {
	private String name;
	private int age;

	public Cat() {
		System.out.println("构造器中:" + this);	//当前创建的对象
	}
	public void say() {
		System.out.println("say方法中:" + this);	//当前调用say方法的对象
		System.out.println("名字=" + this.name + ",年龄=" + this.age);
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

测试代码:

public class ThisDemo {
	public static void main(String[] args) {
		Cat c1 = new Cat();	//此时构造中的this就是当前创建的c1对象
		c1.setName("加菲");
		c1.setAge(5);
		c1.say();	//此时say方法中的this就是c1对象
		
		Cat c2 = new Cat();//此时构造中的this就是当前创建的c2对象
		c2.setName("Tom");
		c2.setAge(3);
		c2.say();	//此时say方法中的this就是c2对象
	}
}

运行测试:

构造器中			:cn.wolfcode._01_this.Cat@15db9742
say方法中			 :cn.wolfcode._01_this.Cat@15db9742
名字=加菲,年龄=5
构造器中			:cn.wolfcode._01_this.Cat@6d06d69c
say方法中		    :cn.wolfcode._01_this.Cat@6d06d69c
名字=Tom,年龄=3

什么时候需要使用this:

  • 解决局部变量和成员变量之间的二义性,此时必须使用
  • 同一个类中非static方法间互调(此时可以省略this,但是不建议省略)
  • 构造器重载的互调(看懂即可)
public class Dog {
	private String name;
	private int age;

	public Dog() {
	}

	public Dog(String name) {
		this(name, 0);// 调用两个参数的构造器,必须放在构造器第一行
		// TODO其他操作
	}

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

	public void say() {
		String name = "局部变量";
		System.out.println(name); 		// 访问局部变量
		System.out.println(this.name);	// 访问成员变量
		this.other();// 调用当前类中非static方法
	}

	public void other() {
		System.out.println(this.age);//此时的this是谁
	}
}
13.2. super关键字(重点掌握)

什么是super:

this :表示当前对象,谁调用this所在的方法,this就是哪一个对象

super :当前对象的父类对象

在创建子类对象时,在子类构造器的第一行会先调用父类的构造器。

什么时候使用super:

  • 在子类方法中,调用父类被覆盖的方法,此时必须使用super
  • 在子类构造器中,调用父类构造器,此时必须使用super语句

父类代码:

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

	public Person() {
	}
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public void doWork() {
		System.out.println("Person...doWork...");
	}
}

子类代码:

public class Student extends Person {
	private String sn;

	public Student(String sn) {
		super();// 隐式调用父类无参数构造器,必须作为构造第一行
		this.sn = sn;
	}
	public Student(String name, int age, String sn) {
		super(name, age);// 显示去调用父类无参数构造器,必须作为构造第一行
		this.sn = sn;
	}
	public void doWork() {
		super.doWork();	//	?此时调用谁的方法
		this.doWork();	//	?此时调用谁的方法
		System.out.println("Student...doWork...");
	}
}
13.3. static修饰符(掌握)

static修饰的字段和方法直接属于类,不属于该类的对象。记住:字段和方法属于谁,就让谁来调用。

  • 使用static修饰的成员: 属于类 直接使用类名调用即可
  • 没有使用static修饰的成员: 属于对象 必须先创建对象,再调用

注意:static方法不能使用super和this:

因为static是类级别的,super和this是对象级别的,存在类的时候不一定存在对象,也就说使用类名调用static方法时,此时可能是没有对象的。

测试代码:

public class Dog {
	public static int totalNumber = 100;
	public int age;

	public void m1() {
		System.out.println("实例方法");
	}

	public static void m2() {
		System.out.println("静态方法");
	}
}
public class StaticDemo {
	public static void main(String[] args) {
		Dog d1 = new Dog();
		d1.age = 5;

		Dog d2 = new Dog();
		d2.age = 15;
         //调用代码再后面
	}
}

内存分析:

static修饰的成员变量(字段),随着所在类被加载进JVM,也同时存储在方法区中,被所有对象共享

**[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-41HZdPaD-1693278427627)(img\图片 1_7.png)]**

实例成员和类成员的访问规则:

d1.m1();//	实例方法
d2.m1();//	实例方法
// Dog.m1(); 语法报错

d1.m2();//静态方法	 底层使用类名访问
d2.m2();//静态方法	 底层使用类名访问
d1.m2();//静态方法	 底层使用类名访问
Dog.m2();

System.out.println(d1.age);// 5
System.out.println(d2.age);// 15
// System.out.println(Dog.age); 语法报错

System.out.println(d1.totalNumber);//100	 底层使用类名访问
System.out.println(d2.totalNumber);//100	 底层使用类名访问
System.out.println(Dog.totalNumber);//100

使用对象访问static方法或成员变量,底层依然使用类名访问的。

一般的,static方法访问的成员变量必须使用static修饰。

最后记住结论:

  • 类 成 员:使用static修饰的字段和方法 : 属于类 直接使用类名调用即可
  • 实例成员:没有使用static修饰的字段和方法: 属于对象 必须先创建对象,再调用
13.4. final修饰符(掌握)

​ 继承关系最大弊端是破坏封装,子类可以继承父类的实现细节,也可以通过方法覆盖的形式修改功能实现细节。那么怎么来限制某个类不能有子类,不能覆盖方法?——final修饰符。

final的含义是最终的,不可改变的,可以修饰类、方法、变量。

  • final修饰的类:表示最终的类, 该类不能再有子类
final public class Super {
}
public class Sub  extends Super{	//此行语法报错
}

  • final修饰的方法:最终的方法,该方法不能被子类覆盖
public class Super {
	final public void doWork() {
	}
}

public class Sub  extends Super{
	public void doWork() {		//此行语法报错
	}
}

  • final修饰的变量:表示常量,该变量只能赋值一次,不能再重新赋值。
    • 基本数据类型:表示的值不能改变
    • 引用数据类型:所引用的地址值不能改变
final int age = 17;
age = 100;	//此行语法报错

final Dog d = new Dog();
d.setAge(5);	//d的字段值是可以改变的	
d = new Dog();	//此行语法报错

13.5. 代码块(了解)

什么是代码块:直接使用{}括起来的一段代码区域。

代码块里变量属于局部变量,只在自己所在区域{}内有效。

存在三种形式:

  • 局部代码块: 直接定义在方法内部的代码块,一般的,不会直接使用局部代码块的,结合if、while、for等关键字使用,表示一块代码区域。
public class CodeBlockDemo {
	public static void main(String[] args) {
		System.out.println("begin...");
		{
			//直接使用代码块,一般不用
			int age = 17;
		}
		System.out.println(age);	//此行报错,超出age作用范围,就不能访问到了
		if (100 > 5) {
			System.out.println("100 > 5");
		}
		System.out.println("end...");
	}
}

  • 初始化代码块(构造代码块):直接定义在类中。每次创建对象的时候都会执行初始化代码块,开发中不使用初始化代码块,即使要做初始化操作,可以直接在构造器中完成即可。
  • 静态代码块:使用static修饰的初始化代码块,当该代码块的类的字节码被加载进JVM,就执行static代码块代码。在开发中,用来做加载资源、加载配置文件等操作。

分析下面代码执行顺序:

public class Fish {
	{
		System.out.println("初始化代码块...");
	}
	static {
		System.out.println("静态代码块...");
	}
	public Fish() {
		System.out.println("构造器");
	}
	
	public static void main(String[] args) {
		System.out.println("主方法...");
		new Fish();
		new Fish();
	}
}

运行结果:

静态代码块...
主方法...
初始化代码块...
构造器
初始化代码块...
构造器

13.6. 内部类和匿名内部类(了解)

什么是内部类,把一个类定义在另一个类的内部,把里面的类称之为内部类,把外面的类称之为外部类。(能认识内部类即可)

**[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U0ZA91Ob-1693278427629)(img\图片 2_7.png)]**

内部类可以看作和字段、方法一样,是外部类的成员,而成员可以有static修饰。

  • 静态内部类:使用static修饰的内部类,那么访问内部类直接使用外部类名来访问
  • 实例内部类:没有使用static修饰的内部类,访问内部类使用外部类的对象来访问
  • 局部内部类:定义在方法中的内部类,一般不用
  • 匿名内部类:特殊的局部内部类,适合于仅使用一次使用的类

对于每个内部类来说,Java编译器会生成独立.class文件。

  • 静态和实例内部类:外部类名$内部类名字-
  • 局部内部类:外部类名$数字内部类名称
  • 匿名内部类:外部类名$数字
13.6.1. 匿名内部类(重点掌握)

在多态USB的案例中,当新增一种USB规范的设备,此时需要单独使用一个文件来定义一个新的类。

比如,新增一个USB规范的打印机设备。

public class Print implements IUSB{
	public void swapData() {
		System.out.println("打印....");
	}
}

把打印机安装在主板上。

public class USBDemo {
	public static void main(String[] args) {
		// 创建主板对象
		MotherBoard board = new MotherBoard();
		// 创建打印机对象
		Print p = new Print();
		//把打印机安装在主板上
		board.plugin(p);
	}
}

​ 如果这一个Print类只需要使用一次的话,就完全没有必要单独定义一个Java文件,直接使用匿名内部类来完成。

​ 匿名内部类,可以使用父类构造器和接口名来完成。

针对类,定义匿名内部类来继承父类(使用较少):

new  父类构造器([实参列表]){ 
     //匿名内部类的类体部分
}

针对接口,定义匿名内部类来实现接口(使用较多):

new  接口名称(){ 
     //匿名内部类的类体部分
}

注意:这里不是根据接口创建对象,而是一种语法而已。

board.plugin(new IUSB() {
	public void swapData() {
		System.out.println("打印...打印...");
	}
});

其实匿名内部类,底层依然还是创建了一份字节码文件USBDemo$1,其反编译代码为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-32TiMnvk-1693278427629)(img\图片 3_6.png)]

13.7. 枚举类(掌握)
13.7.1. 枚举的诞生史(了解)

在服装行业,衣服的分类根据性别可以表示为三种情况:男装、女装、中性服装。

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

需求:定义一个变量来表示服装的分类?请问该变量的类型使用什么?

使用int和String类型,且先假设使用int类型,因为分类情况是固定的,为了防止调用者乱创建类型,可以把三种情况使用常量来表示。

public class ClothType {
	public static final int MEN = 0;
	public static final int WOMEN = 1;
	public static final int NEUTRAL = 2;
}

注意:常量使用final修饰,并且使用大小字面组成,如果是多个单词组成,使用下划线分割。

​ 此时调用setType方法传递的值应该是ClothType类中三个常量之一。但是此时依然存在一个问题——依然可以乱传入参数比如100,此时就不合理了。

​ 同理如果使用String类型,还是可以乱设置数据。那么说明使用int或String是类型不安全的。那么如果使用对象来表示三种情况呢?

public class ClothType {
	public static final ClothType MEN =  new ClothType();
	public static final ClothType WOMEN =  new ClothType();
	public static final ClothType NEUTRAL =  new ClothType();
}

​ 此时调用setType确实只能传入ClothType类型的对象,但是依然不安全,为什么?因为调用者可以自行创建一个ClothType对象,如:setType(new ClothType())。

​ 此时为了防止调用者私自创建出新的对象,我们把CLothType的构造器私有化起来,外界就访问不了了,此时调用setType方法只能传入ClothType类中的三个常量。此时代码变成:

public class ClothType {
	public static final ClothType MEN =  new ClothType();
	public static final ClothType WOMEN =  new ClothType();
	public static final ClothType NEUTRAL =  new ClothType();
	private ClothType() {}
}

高,实在是高!就是代码复杂了点,如果存在定义这种类型安全的且对象数量固定的类的语法,再简单点就更好了——有枚举类。

13.7.2. 枚举类的定义和使用(掌握)

枚举是一种特殊的类,固定的一个类只能有哪些对象,定义格式:

public enum  枚举类名{
      常量对象A, 常量对象B, 常量对象C ;
}

我们自定义的枚举类在底层都是直接继承了java.lang.Enum类的。

public enum ClothType {
	MEN, WOMEN, NEUTRAL;
}

枚举中都是全局公共的静态常量,可以直接使用枚举类名调用。

ClothType type = ClothType.MEN;

因为java.lang.Enum类是所有枚举类的父类,所以所有的枚举对象可以调用Enum类中的方法.

String	name = 枚举对象.name();  		//	返回枚举对象的常量名称
int	ordinal  = 枚举对象.ordinal();	//	返回枚举对象的序号,从0开始

int ordinal = 枚举对象.ordinal(); // 返回枚举对象的序号,从0开始

注意:枚举类不能使用创建对象

public class EnumDemo {
	public static void main(String[] args) {
		int ordinal = ClothType.MEN.ordinal();
		String name = ClothType.MEN.name();
		System.out.println(ordinal);
		System.out.println(name);
		new ClothType();	//语法报错
	}
}

目前,会定义枚举类和基本使用就可以了,后面还会讲更高级的使用方式。

学习优势:

1.包含java前后端从 0 ->1 全过程教学, 内容全面, 知识点不遗漏, 学完即可参加实际工作.
2.课程为目前项目开发常用的技术知识,向用人单位对标,学以致用。那些脱离实际,废弃不用的,太前沿的框架技术前期不建议学。
3.一起学习,打卡,一起交流,希望能营造一个和线下一样的学习环境。

需要进微信学习交流群, 或者想领取代码,文档,全套视频的同学请+v:lmm99964

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值