类与对象

一、相关定义



类(class)是构造对象的模板或蓝图 。由类 构造对象的过程称为创建类的实例。

封装
从形式上来看封装是将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式。对象中的数据称为实例域,操纵数据的过程称为方法。对于每个特定的类实例(对象)都有一组特定的实例域值。这些值的集合就是这个对象的当前状态。无论何时,只要向对象发送一个消息,它的状态就可能发生改变。

类之间最常见的关系有:
• 依赖
• 聚合
• 继承

依如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。应该尽可能地将相互依赖的类减至最少。
聚合,聚合关系意味着类A的对象包含类B的对象。
继承,一般而言如果类A扩展类B,类A不但包含从类B继承的方法,还会拥有一些额外的功能。

对象
对象的三个特性:
• 对象的行为(behavior)——可以对对象施加哪些操作,或可以对对象施加哪些方法?
• 对象的状态(state)——当施加那些方法时,对象如何响应?
• 对象标识(identity)——如何辨别具有相同行为与状态的不同对象?

同一个类的所有对象实例,由于支持相同的行为而具有家族式的相似性。对象的行为是可调用的方法定义的。
每个对象都保存着描述当前特征的信息,这就是对象的状态。对象的状态可能会随着时间而发生改变,但这种改变不会是自发的。对象状态的改变必须通过调用方法实现(如果不经过方法调用就可以改变对象状态,只能说明封装性遭到了破坏)。
对象的状态不能完全描述一个对象,每个对象都有一个唯一的身份。作为一个类的实例,每个对象的标识永远是不同的,状态常常也存在着差异。
对象的这些关键特性在彼此之间相互影响着,例如状态影响着它的行为。

二、使用预定义类


在对象与对象变量之间存在着一个重要的区别。例如:

Date deadline;

定义了一个对象变量deadline,它可以引用Date类型的对象。但是deadline不是一个对象,实际上也没有引用对象。此时,不能将任何Date方法应用于这个变量上。

一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。在Java中,任何对象的值都是对存储在另外一个地方的一个对象的引用。new操作符的返回值也是一个引用。

三、用户自定义类


构造器与其他方法有一个重要的不同。构造器总是伴随着new操作符的执行被调用,而不能对一个已经存在的对象调用构造器来达到重新设置实例域的目的。
• 构造器与类同名
• 每个类可以有一个以上的构造器
• 构造器可以有0个、1个或多个参数
• 构造器没有返回值
• 构造器总是伴随着new操作一起调用

隐式参数,是出现在方法名前面的xxx类对象。
显式参数,是位于方法名后面括号中的数值。
在每一个方法中,关键字this表示隐式参数。

在实现一个类时,由于共有数据非常危险,所以应该将所有的数据域都设置为私有的。大多数方法被设置为公有的,但在某些特殊情况下,也可能将他们设置为私有的。有时,可能希望将一个计算代码划分为若干个独立的辅助方法。通常,这些辅助方法不应该成为公有接口的一部分,这是由于它们往往与当前的实现机制非常紧密,或者需要一个特别的协议以及一个特别的调用次序,最好将这种方法设计为private的。

可以将实例域定义为final。构造对象时必须初始化这样的域。也就是说,必须确保在一个构造器执行之后,这个域的值被设置,并且在后面的操作中,不能够再对它进行修改。
final修饰符大都应用于基本类型域,或不可变类的域(如果类中的每个方法都不会改变其对象,这种类就是不可变的类。例如String类。)
对于可变的类,使用final

private final StringBuilder eva;
eva = new StringBuilder();

final关键字只是表示存储在eva变量中的引用对象不会再指示其他StringBuilder对象。不过这个对象可以改变。

四、静态域与静态方法


如果将域定义为static, 每个类中所有对象共享一个静态域。而每一个对象对于所有的实例域却都有自己的一份拷贝。

class Employee{
	private static int nextId = 1;
	private int id;
} 

现在每一个雇员对象都有一个自己的id域,但这个类的所有实例将共享一个nextId域。如果有1000个Employee类的对象,则有1000个实例域id,但是只有一个静态域nextId。即使没有一个雇员对象,静态域nextId也存在,它属于类,而不属于任何独立的对象。

静态常量 如Math中的PI,可以通过Math.PI的形式获得这个常量。

静态方法是一种不能向对象实施操作的方法。例如Math.pow(x,a)在运算时不使用任何Math对象。换句话说没有隐式的参数。
不能在静态方法中访问实例域,但是,静态方法可以访问自身类中的静态域。
可以使用对象调用静态方法,不过建议使用类名来调用。
静态方法还有另一种常见的用途。类似LocalDate和NumberFormat的类使用静态工厂方法来构造对象。如:

NumberFormat curr = NumberFormat.getCurrencyInstance();
NumberFormat per = NumberFormat.getPercentInstance();

为什么不用构造器完成?
• 无法命名构造器。构造器的名字必须与类名相同,但是这里希望得到的货币实例和百分比实例采用不同的名字。
• 当使用构造器时,无法改变所构造的对象类型。而工厂方法将返回一个DecimalFormat类对象,这是NumberFormat的子类。

五、方法参数


Java程序设计语言总是采用 按值调用。也就是说,方法得到的是所有参数值的一个拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。

方法参数共有两种类型:
• 基本数据类型(数字、布尔值)。
• 对象引用。

基本数据类型:
现有一个方法

public static void tripleValue(double x){
		x = x * 3;
	}
	
	double a = 10;
	tripleValue(a);

调用这个方法之后a的值还是10。这个方法具体的执行过程:
1. x被初始化为a值的一个拷贝(也就是10)。
2. x被乘以3后等于30。但是a的值仍然是10。
3. 这个方法结束之后参数变量x不再使用。

对象引用:
对象引用作为参数,可以很容易地利用下面这个方法实现将一个雇员的薪金提高两倍的操作:

public static void tripleSalary(Employee x){
	x.raiseSalary(200);
}

harry = new Employee();
tripleSalary(harry);

具体执行过程:
1. x被初始化为harry值的拷贝,这是一个对象的引用。
2. raiseSalary方法应用于这个对象引用。x和harry同时引用的那个Employee对象的薪金提高了200%。
3. 方法结束后,参数变量x不再使用,但对象变量harry继续引用那个薪金增值3倍的雇员对象。

总结一下Java中方法参数的使用情况:
• 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)。
• 一个方法可以改变一个对象参数的状态。
• 一个方法不能让对象参数引用一个新的对象。

六、对象构造

类有多个构造器,这种特征叫做重载

如果在构造器中没有显式地给域赋予初值,那么就会被自动地赋为默认值:数值为0、布尔值为false、对象引用为null。(如果不明确地对域进行初始化,就会影响程序代码的可读性)

如果在编写一个类时没有编写构造器,那么系统就会提供一个无参构造器。这个构造器所有的实例域设置为默认值。
如果类中提供了至少一个构造器,但是没有提供无参构造器,则在构造对象时如果没有提供参数就会被视为不合法。

如果构造器的第一个语句形如this(…),这个构造器将调用同一个类的另一个构造器。

public Employee(double s){
		//这里会调用Employee(string,double)
		this("sss",s);} 

初始化块。例:

class Employee{
		private static int nextId;
		
		private int id;
		private String name;
		private double salary;
		
		//初始代码块
		{
			id=nextId;
			nextId++;
		}
		
		public Employee(){
			name="";
			Salary=0;
		}
	}

无论使用哪个构造器构造对象,id域都在对象初始化块中被初始化。首先运行初始化块,然后再运行构造器的主体部分。
调用构造器的具体处理步骤:
1. 所有数据域被初始化为默认值(0、false或null)。
2. 按照在类声明中出现的次序,依次执行所有域初始化语句和初始化块。
3. 如果构造器第一行调用了第二个构造器,则执行第二个构造器主体。
4. 执行这个构造器的主体。

如果对类的静态域进行初始化的代码比较复杂,那么可以使用静态的初始化块。例:

static
	{
		Random gen = new Random();
		nextId = gen.nextInt(10000);
	}

在类的第一次加载时,会对静态域初始化。与实例域一样,除非将他们显示初始化,否则都设为默认值。所有的静态初始化语句以及静态初始化块都将依照类定义的顺序执行。

七、包


使用包的主要原因时确保类名的唯一性。为了保证包名的绝对唯一性,Sun公司建议将公司的因特网域名以逆序的形式作为包名。例如prongs.com 逆序形式为com.prongs。

静态导入

Import static java.lang.System.*

则使用的时候不必加类名前缀例:out.println("love");

将类放入包中,就必须将包的名字放在源文件的开头package com.prongs.test;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值