JAVA中的类和对象

前言

李刚老师《JAVA疯狂讲义》第5版,第5章学习笔记。

1.类的定义

什么是JAVA中的类呢?

JAVA中的类是一种引用类型,类用于描述客观世界中,某一类对象的共同特征,比如:水果是一类对象、NBA球员是一类对象、哺乳类动物是一类对象。
利用类,可以定义变量,类是一种引用类型,定义的变量是引用变量。那么这个引用变量到底指向哪里呢?指向的就是类的对象,对象就是具体存在的实体,引用变量就是指向这个实体的指针。
比如类是NAB球员,创建的引用变量就是勒布朗.詹姆斯这个球员名,这个名字就是个指针,通过这个名字,你可以找到勒布朗.詹姆斯真正的实体对象,查到他的各项数据(成员变量),查到他会的各项篮球技能等(方法)。这就是类、引用变量、对象的含义。

JAVA中类的定义语法如下:

public/final/abstract class 类名
{

	0-n个成员变量;
	0-n个方法;
	0-n个构造器;
}

其中,public,final,abstract修饰符可以三选其一,或者没有修饰符。
可见,JAVA中定义一个类包含三部分:

  1. 定义成员变量
  2. 定义方法
  3. 定义构造器

类中的成员变量用于定义类,或者类的对象所包含的状态数据。例如NBA球员这个类,所有NBA球员的平均年龄就是类的状态数据,勒布朗.詹姆斯的年龄就是类的对象的状态数据。定义成员变量的语法如下:

public/protected/private(static)(final) 类型 成员变量名 = 默认值;

其中,修饰符部分,public,protected,private 3选1或0,static,final可以同时出现,相互组合形成成员变量的修饰符。

类型部分,可以是JAVA支持的所有数据类型,包括基本数据类型和引用数据类型。

成员变量名部分,在满足语法规则的基础上,尽量保证可读性,含义明确。

默认值部分,可以指定成员变量的默认值。

类中的方法用于定义类,或者类的实例的行为、功能,例如NBA球员是这个类,所有的NBA球员都会打篮球,有打篮球这个方法,这就是类的功能,勒布朗.詹姆斯会上篮就是类的实例的行为、功能。定义语法如下:

public/protected/private/(static)(final/abstract) 方法返回值类型 方法名(形参列表)
{
	//0-n条可执行语句组成的方法执行体
}

其中,修饰符部分,public/protected/private 3选1或0,abstract/final 2选1或0, 都可以与static组合。

方法返回值类型部分,方法的返回值可以是JAVA所支持的所有数据类型(基本类型和引用类型),如果声明了方法返回值类型,则方法体内必须有return语句返回数据,并且数据类型必须匹配。如果没有声明方法返回值类型,则必须使用void来生命。

方法名部分,命名规则与成员变量基本类似。

形参列表部分,用于定义该方法可以接受的参数,形参列表由0组到多组的"参数类型 形参名"组合而成,各组之间用","隔开。一旦指定了形参列表,则在调用该方法时,必须传入相应参数值。

类中的构造器用于创建类的对象。如果一个类没有构造器,则JAVA系统会为该类提供一个默认的构造器。一旦类中有自己定义的构造器,那么JAVA系统将不会提供默认构造器。定义构造器的语法如下:

public/protected/private 构造器名(形参列表)
{
	//0-n条可执行语句组成的构造器执行体
}

构造器是一种特殊的方法,因此语法格式与方法的语法格式很像。

其中,public,protected,private修饰符可以三选其一,或者没有修饰符。构造器名必须和类名完全相同。形参列表和定义方法的形参列表格式基本相同。

注意:
构造器不能定义返回值的类型,也不能使用void声明没有返回值。因为实际上,构造器是有返回值的,返回值就是当前类的实例。如果加入了这些内容,JAVA编译器并不会报错,但是会把构造器当作普通方法使用。

以下程序将定义一个NBA球员类:

public static class NBAplayer{
	//定义成员变量
	public String name;
	public int age;
	//定义方法
	public void playPosition(String position){
		System.out.println("这名球员的位置是:" + position);
	}
}

上述NBAplayer类中,并未定义构造器,会由系统自动提供一个构造器。

2.对象的创建和使用

对象是类的实例,对象通过类的构造器来创建,通过new关键字来调用某个类的构造器就可以创建这个类的对象:

NBAplayer p = new NBAplayer();

这一行代码产生了两个东西:引用变量p和NBAplayer这个类的对象。其中,new NBAplayer()是创建了一个对象,NBAplayer p是创建了一个引用变量。
引用变量在内存中储存于栈内存中,类的对象储存在堆内存中,具体如下(JAVA中字符串类型和数组类型都是引用类型):
JAVA类和对象在内存中的存储
其中,栈内存中的p只是储存了一个地址值,指向实际对象的地址值,其本身并未包含任何数据。也可以再创建一个引用变量p1,指向同一个对象,这样,不管是访问p的成员变量和方法,还是访问p1的成员变量和方法,实质上,都是访问堆内存中同一个对象的成员变量和方法。如果希望垃圾回收机制回收某个对象,只需要把所有指向该对象的引用变量赋值为null便可,无应用变量指向的对象会被垃圾回收。
创建完毕后便可对JAVA中的对象进行使用,JAVA中的对象大致有以下作用:访问对象的实例变量,调用对象的方法。语法如下:

//访问对象的实例变量
p.name = "勒布朗.詹姆斯";
System.out.println(p.name);
//调用对象的方法
p.playPosition("小前锋");

注意:
static修饰的方法和成员变量,可以通过类来调用,也可以通过类的实例来调用;没有使用static修饰的方法和成员变量,只可以通过类的实例来调用。关于类、成员变量、方法的修饰符会在后续的文章中详细讲解。

3.对象的this引用

JAVA中的this总是指向调用该方法的对象,this作为对象的默认引用有以下两种情形:

  1. 构造器中,引用该构造器正在初始化的对象
  2. 方法中,引用调用该方法的对象

第一种情形,例如:

//这里定义为静态类,因为main方法为静态方法
public static class ThisInConstuctor{
	//定义一个名为foo的变量
	public int foo;
	//定义一个构造器
	public ThisInConstuctor(){
		//int foo = 0;
		//下方this代表构造器正在初始化的对象
		this.foo = 6;
	}
}
public static void main(String args[]) {
	System.out.println(new ThisInConstuctor().foo);
}

可见,构造器得到的类的对象的foo成员变量被赋值为6,因为在构造器中,this代表构造器正在初始化的对象,对其成员变量赋值为6。在大部分时候,在构造器中访问其他成员变量、方法时,this都可以省略(这只是为了语法上的简洁,实际上,这个this是依旧存在的)。但是,当构造器中有一个局部变量和成员变量重名,但还是必须在构造器中访问这个成员变量,那么必须加入this前缀。

第二种情形,例如:假设定义了一个Dog类,这个Dog类对象的run()方法需要调用他自己的jump()方法,那么是否需要下面这样做呢:

	public static class Dog{
		//定义jump方法
		public void jump() {
			System.out.println("这是jump方法");
		}
		//定义run方法,run方法中需要调用jump方法
		public void run() {
			Dog d = new Dog();
			d.jump();
			System.out.println("这是run方法");
		}
	}

就是在run()方法中,又重新创建了一个Dog对象,那么,当使用run()方法时,就需要两个Dog对象,一个是调用run()方法的Dog对象,一个是run()方法里面,自己又偷偷摸摸创建的一个Dog对象。这无疑是非常麻烦的,占空间的,也是不易解释的。一个狗能不能跑,取决于另一条狗能不能跳。借助this关键字就可以解决这个问题:

	public static class Dog{
		//定义jump方法
		public void jump() {
			System.out.println("这是jump方法");
		}
		//定义run方法,run方法中需要调用jump方法
		public void run() {
			this.jump();
			System.out.println("这是run方法");
		}
	}

this就代指调用该方法的对象,显然,调用该方法的对象有jump()方法。从逻辑上也能解释的通,一个狗能不能跑,取决于这条狗能不能跳,而不是别的狗。

实际生活中,对象的一个方法依赖于这个对象的另一个方法是非常常见的,因此,为了语法简洁起见,方法中的this也可以省略(与构造器相同,省略是为了简洁,但是this依旧是存在的)。

但是,对于statci修饰的方法(静态方法),不能使用this引用。比如说定义了一个NBAplayer类,static修饰的方法可以用这个类直接调用,无需指明对象,那么在调用这个类的静态方法时,如果静态方法中出现了this关键词,这个this就找不到对象了,因为this永远指向的是对象,那么就会出错。所以,static修饰的方法不能使用this引用。

引申一步,由于this关键词大部分情况下可以省略,而static修饰的方法中不能使用this引用,因此static修饰的方法中不能访问不适用static修饰的普通成员,因为这些成员其实前面偷偷藏着this这个关键词。也就是说,静态成员不能直接访问非静态成员。

具体来讲,在面向对象的编程世界里,语法格式遵守严格的主谓宾结构,例如勒布朗会打篮球这个实际生活中的场景,转化为面向对象的编程就应该写成:勒布朗.打(篮球)。在JAVA中,即使代码省略了主语(勒布朗),但是实际的主语依旧是存在的。对于static修饰的方法、成员变量,省略的主语就是这个类(NBA球员),对于没有static修饰的方法、成员变量,省略的主语就是这个对象(勒布朗),this只可以指向调用这个方法、构造器的对象,而不能指向类。

例如,下方代码将会报错:

	public static class StaticAccessNonStatic{
		public void info() {
			System.out.println("这是一个非静态类");
		}
		public static void main(String args[]) {
			info();
		}
	}

由于info是非静态方法,前面省略了this,所以静态方法main调用时会报错,如果真的需要在静态方法中调用非静态方法,则需要创建一个对象来调用,如下:

	public static class StaticAccessNonStatic{
		public void info() {
			System.out.println("这是一个非静态类");
		}
		public static void main(String args[]) {
			StaticAccessNonStatic p = new StaticAccessNonStatic();
			p.info();
		}
	}

除此之外,this比较有趣的一点是,程序可以像访问普通引用变量一样,访问this,甚至可以把this当作普通方法的返回值。例如:

	public static class ReturnThis{
		public int age;
		public ReturnThis grow() {
			age++;
			return this;
		}
	}
	public static void main(String args[]) {
		ReturnThis rt = new ReturnThis();
		rt.grow().grow().grow();
		System.out.println("当前年龄为:"+rt.age);
	
	}

ReturnThis类中的grow()方法的返回值为this,也就是返回了一个ReturnThis对象,这个对象又可以调用grow()方法,因此,借助this,一个对象可以反反复复的调用方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值