2. 类和对象的本质

类和对象的本质

类的本质

8种基本数据类型,当我们需要什么类型,即把它自定义出来

class 自定义数据类型 User

过程中结合属性和方法进行描述,类中不能调用操作

使用: int i = 10; 使用i就必须声明(包括数据类型)和初始化,进一步在程序中使用变量i参与运算

User user(类类型产生的变量,对象) = new User();

User是类型,user是一个对象,经过赋值,user对象就进行了实例化,所以,对象user是User的一个实例 ,

赋值过程: new User(); 

如果没有经过new赋值, 那么对象会存在一个默认值: null

类类型(class声明的)也叫做对象类型

对象类型有三种:

- class声明的自定义的类
- String类型(本质上还是class类型)
- 数组 int\[\] arr = new int\[length\]; 因为对象类型可以定义属性和方法(为了得到length)

对象的本质

对象的本质,是类的实例(instance/ initialize 实例化 )

实例化的过程: 通过 new className() 分配内存, 再将内存首地址传递给对象 ,所以,对象是引用了一段内存的首地址

所以, 对象类型也可以叫做引用(reference)类型

Reference: 引用, 相当于电视的遥控器

如果对象没有初始化(未引用地址,此时对象保存的是默认值null), 而null是不能去执行操作的,如果执行则抛出异常: NullPointerException

为什么不能用 new User() 直接作为操作的对象?

new User() 虽然不能做二次操作, 但如果只执行一次? 可以的

类和对象的关系

类是公共的模板,对象是具体的个体

类是公共的类型,对象是实例

类负责描述,对象负责执行

类和对象在内存中的图例

堆内存和栈内存: 堆的速度慢不适合反复操作 , 栈适合快速读写和适合反复操作
在这里插入图片描述

通过对象直接给对象赋值以及对象为null的情况

public static void main(String[] args) {
		// 用User生成对象
		User user1 = new User();
		user1.name = "任心悦";
		
		
		User user2 = user1;
		user2.name = "姜志伟";
		
		System.out.println("user1:"+user1);
		System.out.println("user2:"+user2);
		
		System.out.println("user2.name:"+user2.name);   //姜志伟
		System.out.println("user1.name:"+user1.name);  	//姜志伟
		
		// new User() 也是一个垃圾内存
		// 应用场景: 只需要调用一次操作时适合使用(窗体swing)
		System.out.println(new User());
		new User().name = "张学友";
		System.out.println(new User().name);  //null 字符串的默认值
		
		
		// null是所有对象类型的默认值
		User user3 = null ;
		System.out.println("user3:"+user3);
		 // java规定null对象不能执行调用操作,否则抛出NullPointerException
		user3.name = "张曼玉"; 
		
	}

new 关键字

  • 调用构造方法

  • 开辟内存

  • 传递引用: 传递引用给对象

构造方法

User()

概念

方法名和类名完全一致(包括大小写),没有返回值的一个方法,定义类当中

使用

只能通过new 来调用, 在对象被实例化的时候

特点:

  1. 每一个类都有一个默认的构造方法,形式:

ClassName(){}

  1. 默认构造方法(隐式构造方法)可以被覆盖, 覆盖它的构造方法称为显式构造方法

    public class User {
    	
    	// 用户编号
    		String id ;
    		
    		// 用户姓名
    		String name;
    		
    		// 用户手机
    		String phone;
    		
    		// 用户密码
    		String pwd;
    		
    		//用户年龄
    		int age;
    	
    	//int i ;
    	// 主动创建一个构造方法:
    	/*
    	 * User(){ System.out.println("这是一个User的构造方法"); }
    	 */
    
    	// 通过构造方法的参数给类中的成员字段赋初值
    	User(String name,String phone,int age){		
    		// 在构造方法中给i赋值
    		//i = 10;
    		
    		this.name = name;
    		this.age = age;
    		this.phone = phone;
    		
    	}
    	
    	// 如果要使用空参的构造方法, 利用重载
    	// 重载: 类中存在多个方法,它们的方法名相同,参数不同,
    	//它们之间就形成了重载,用overload表示
    	User(){
    		// 构造方法之间可以互相调用:  this()
    		// 调用带phone参数的构造方法:
    		this("13312345678");
    	}
    	
    	User(String phone){
    		this.phone = phone;
    	}
    }
    

构造方法的重载

重载的概念

​ 类中存在多个方法,它们的方法名相同,参数不同,它们之间就形成了重载,用overload表示

下面, 我们利用重载的概念对构造方法进行加工:

// 通过构造方法的参数给类中的成员字段赋初值
	User(String name,String phone,int age){		
		// 在构造方法中给i赋值
		//i = 10;
		
		this.name = name;
		this.age = age;
		this.phone = phone;
		
	}
	
	// 如果要使用空参的构造方法, 利用重载
	// 重载: 类中存在多个方法,它们的方法名相同,参数不同,
	//它们之间就形成了重载,用overload表示
	User(){
		// 构造方法之间可以互相调用:  this()
		// 调用带phone参数的构造方法:
		this("13312345678");
	}
	
	User(String phone){
		this.phone = phone;
	}

作用:

  1. 让对象能够被实例化(实操中主要的职能)

  2. 将对象一开始就需要执行的操作定义在构造方法中

  3. 通过参数给属性赋初值(非必要)

类中的全局和局部作用域:

定义在方法的参数/内部的变量name是局部的作用域(只能在方法内访问)

如果全局和局部具有相同的名称的变量, 局部变量的优先级更高(就近原则)

java中使用this 区分属性和方法中的同名变量

		// 用户姓名
		String name;
		
		// 用户手机
		String phone;
		
		//用户年龄
		int age;
// 通过构造方法的参数给类中的成员字段赋初值
	User(String name,String phone,int age){
		
		this.name = name;
		this.age = age;
		this.phone = phone;
		
	}

this关键字

关键字, 作用相当于对象,只能在类的内部的方法中使用, 可以表示对象

作用

用于区分全局和局部同名的内容,当通过this调用的内容都是类中定义的

// 通过构造方法的参数给类中的成员字段赋初值
	User(String name,String phone,int age){
		
		// 在构造方法中给i赋值
		//i = 10;
		
		this.name = name;
		this.age = age;
		this.phone = phone;
		
	}

植物大战僵尸的设计

public class Zombie {
	// 字段(属性)
	// 攻击力
	int attack;

	// 防御力
	int defense;

	// 生命值
	int hp;

	// 名字
	String name;

	// 方法
	// 构造方法

	Zombie(String name, int attack, int defence, int hp) {
		this.name = name;
		this.attack = attack;
		this.defense = defence;
		this.hp = hp;
	}
	
	/**
	 *再增加一个无参的构造方法 
	 *让对象在创建的时候更加灵活
	 */
	Zombie() {
		
	}
	

	/**
	 * 当僵尸遭遇植物,近战方法
	 * 业务: 僵尸攻击,植物防御,
	 * 攻击次数持续,直到植物的hp<=0,战斗结束
	 */
	void fight(Plant plant) {
		// 在当前类中,可以用this表示自己的对象
		System.out.println(this.name+"开始攻击"+plant.name);
		while (plant.hp>0) {
			plant.hp -= this.attack-plant.defense;
			System.out.println(plant.name+"还剩"+plant.hp+"血");
			
			// 通过Thread.sleep方法让程序停顿
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("战斗结束,"+plant.name+"被"+this.name+"干掉了");
	}

}

java中的三种引用类型

8种基本数据类型是普通数据类型
自定义的类和jdk中已经存在的类型都可以成为对象类型,作用是为了创建对象
对象本质是对内存首地址的引用,对象类型也才被称为引用类型(refence)

  1. 类(首字母大写)

  2. 数组

  3. String

public static void main(String[] args) {
		// 声明一个int的数组
		int[] arr = new int[10];
		
		System.out.println(arr[0]);
		System.out.println(Arrays.toString(arr));
		
		//[I@2401f4c3
		System.out.println(arr);
	}

对象类型赋值的特点,对象类型传递的是内存地址的引用,所以当对象类型之间赋值的时候,这种引用关系会继续传递,本质上是同一个对象

public static void main(String[] args) {
		//先判断栈内存中是否有1的存在,如果有则将该内存指向给a
		//如果没有,就开辟
		//b赋值的时候,判断
		int a = 1; //字面值
		int b = a;  //
		System.out.println("b:"+b);
		b=2;
		System.out.println("b:"+b);
		System.out.println("a:"+a);
		
		
		//换成类型:Plant
		Plant p1 = new Plant();
		p1.name="高坚果";
		
		Plant p2 = p1;
		System.out.println(p2.name);
		p2.name = "窝瓜";
		System.out.println(p2.name);
		System.out.println(p1.name);
	}

String字符串类型虽然也是对象类型, 但java对它做了优化

具体对比情况参考如下代码:

//String传递引用
		/*
		 * String str1 = "abc"; String str2 = str1; str2 = "abcd";
		 * System.out.println("str1:"+str1);
		 */
		
		/*
		 * String str1 = "abc"; String str2 = "abc";
		 * System.out.println(str1.equals(str2)); //true
		 */		
		
		/*
		 * String str1 = "abc"; String str2 = "abcd";
		 * System.out.println(str1.equals(str2)); //false
		 */		
		
		// 当字符串使用new String()的时候, 就不再是在常量池中引用,而是在堆中
		String str1 = new String("abc");
		String str2 = new String("abc");
		
		// == 对象类型使用连等, 比的是内存首地址是否相同
		System.out.println(str1 == str2);   //false , 
		//equals 才是比较内容的方法
		System.out.println(str1.equals(str2));  //true
		
		String str11 = "abc";
		String str22 = "abc";
		System.out.println(str11 == str22);  // true
		System.out.println(str11.equals(str22));  // true
		
		String str111 = "abc";
		String str222 = new String("abc");
		System.out.println(str111 == str222);  // false
		System.out.println(str111.equals(str222));  // true
		
		// java在String常量中的优化
		String str1111 = "abc";
		String str2222 = "ab"+"c";
		System.out.println(str1111 == str2222);  // true
		System.out.println(str1111.equals(str2222));  // true

String在内存中的表现情况

java把字符串的值存放在常量池中, 目的是, 加快字符串的访问速度
在这里插入图片描述
下面代码中会生成几个String对象?

	//创建了几个字符串对象?
	// 答案为2 : "abc"在常量池生成1个, string也是1个
	String string = new String("abc");
	

	// 答案为3 : "abc"在常量池生成1个, str1和str2各一个, 共3个
	String str1 =new String ("abc");
	String str2 =new String ("abc");

final的作用

  1. 声明变量时,表示常量

  2. 声明类, 不能被继承(在继承的章节来学习)

  3. 声明方法, 不能被重写(在多态的章节来学习)

public class Demo3 {
	// final修饰变量, 变为常量, 常量必须赋初值, 之后不可改变
	// 常量一般都建议用全大写命名
	//final int i = 1;
	//final int I = 1;
	 final double PI = 3.14;
	public static void main(String[] args) {
		Demo3 demo3 = new Demo3();
	//	demo3.i = 2;

	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值