面向对象(一遍一遍的领悟)
Java支持面向对象的三大特征:封装、继承和多态,
Java提供 了private、protected和public三个访问控制修饰符来实现良好的封装,提供了extends关键字来让子类继承父类,子类继承父类就可以继承到父类的成员变量和方法,如果访问控制允许,子类实例可以直接调用父类里定义的方法。
继承是实现类复用的重要手段,除此之外也可通过组合关系来实现这种复用,从某种程度上来看,继承和组合具有相同的功能。使用继承关系来实现复用时,子类对象可以直接赋给父类变量,这个变量具有多态性,编程更加灵活;而利用组合关系来实现复用时,则不具备这种灵活性。
构造器用于对类实例进行初始化操作,构造器支持重载,如果多个重载的构造器里包含了相同的初始化代码,则可以把这些初始化代码放置在实例初始化块里完成,实例初始化块总在构造器执行之前被调用。除此之外,Java还提供了一种类初始化块(静态初始化块),类初始化块用于初始化类,在类初始化阶段被执行。如果继承树里的某一个类需要被初始化时,系统将会同时初始化该类的所有父类。所有类是引用类型。。。。。
插入一个重要的祖先类:老祖宗
Object类是所有类、数组、枚举类的父类,也就是说,Java允许把任何类型的对象赋给Object类型的变量。当定义一个类时没有使用extends关键字为它显式指定父类,则该类默认继承Object父类。因为所有的Java类都是Object类的子类,所以任何Java对象都可以调用Object类的方法,例如:
1.boolean equals(Object obj):判断指定对象与该对象是否相等。此处相等的标准是,两个对象是同一个对象,因此该equals()方法通常没有太大的实用价值。
2.protected void finalize():当系统中没有引用变量引用到该对象时,垃圾回收器调用此方法来清理该对象的资源。
3.Class<?> getClass():返回该对象的运行时类,该方法是个类方法,好像还是final修饰。
4.int hashCode():返回该对象的hashCode值。在默认情况下,Object类的hashCode()方法根据该对象的地址来计算(即与System.identityHashCode(Object x)方法的计算结果相同)。 但很多类都重写了Object类的hashCode()方法,不再根据地址来计算其hashCode()方法值。
5.String toString():返回该对象的字符串表示,当程序使用System.out.println()方法输出一个对象,或者把某个对象和字符串进行连接运算时,系统会自动调用该对象的toString()
方法返回该对象的字符串表示。Object类的toString()方法返 回“运行时类名@十六进制hashCode值”格式的字符串,但很多类都重写了Object类的toString()方法,用于返回可以表述该对象信息的字符串。
除此之外,Object类还提供了wait()、notify()、notifyAll()几个方法,通过这几个方法可以控制线程的暂停和运行。
Java还提供了一个protected修饰的clone()方法,该方法用于帮助其他对象来实现“自我克隆”,所谓“自我克隆”就是得到一个当前对象的副本,而且二者之间完全隔离。由于Object类提供的clone()方法使用了protected修饰,因此该方法只能被子类重写或调用。
自定义类实现“克隆”的步骤如下。
①自定义类实现Cloneable接口。这是一个标记性的接口,实现该接口的对象可以实现“自我克隆”,接口里没有定义任何方法。
②自定义类实现自己的clone()方法。
③实现clone()方法时通过super.clone();调用Object实现的clone()方法来得到该对象的副本,并返回该副本。
复制的时候也是分为基本数据类型的复制和引用类型的复制,引用类型的复制只是简单的复制引用类型。Object类提供的clone()方法不仅能简单地处理“复制”对象的问题,而且这种“自我克隆”机制十分高效。比如clone一个包含100个元素的int[]数组,用系统默认的clone方法比静态copy方法快近2倍。但它只是一种“浅克隆”,它只克隆该对象的所有成员变量值,不会对引用类型的成员变量值所引用的对象进行克隆。如果开发者需要对对象进行“深克隆”,则需要开发者自己进行“递归”克隆,保证所有引用类型的成员变量值所引用的对象都被复制了。
通过祖宗类,引申出了Objects工具类,它提供了一些工具方法来操作对象,这些工具方法大多是“空指针”安全的。比如你不能确定一个 引用变量是否为null,如果贸然地调用该变量的toString()方法,则可能引发NullPointerExcetpion异常;但如果使用Objects类提供的toString(Object o)方法,就不会引发空指针异常,当o为null时,程序将返回一个"null"字符串。
提示:
Java为工具类的命名习惯是添加一个字母s,比如操作数组的工具类是Arrays,操作集合的工具类是Collections。
定义类:
public class A{}
修饰符可以是public、final、abstract或者完全省略这三个修饰符,类名只要是一个合法的标识符即可,实际开发中Java类名必须是由一个或多个有意义的单词连缀而成的,每个单词首字母大写,其他字母全部小写,单词与单词之间不要使用任何分隔符。对一个类定义,可以包含三种最常见的成员:构造器、成员变量和方法,三种成员都可以定义零个或多个,如果三种成员都只定义零个,就是定义了一个空类,这没有太大的实际意义。
类里各成员之间的定义顺序没有任何影响,各成员之间可以相互调用,但需要指出的是,static修饰的成员不能访问没有static修饰的成员。
成员变量用于定义该类或该类的实例所包含的状态数据,方法则 用于定义该类或该类的实例的行为特征或者功能实现。构造器用于构 造该类的实例,Java语言通过new关键字来调用构造器,从而返回该类
的实例。
构造器是一个类创建对象的根本途径,如果一个类没有构造器, 这个类通常无法创建实例。因此,Java语言提供了一个功能:如果程序员没有为一个类编写构造器,则系统会为该类提供一个默认的构造器。一旦程序员为一个类提供了构造器,系统将不再为该类提供构造
器。
定义构造器:
修饰符 构造器名{} ,对定义构造器语法格式的详细说明如下。
1.修饰符:可以省略,也可以是public、protected、private其中之一,只有这三种可选。
2.构造器名:构造器名必须和类名相同。
3.形参列表:和定义方法形参列表的格式完全相同。
注意:
构造器既不能定义返回值类型,也不能使用void声明构造器没有返回值。如果为构造器定义了返回值类型,或使用void声明构造器没有返回值,编译时不会出错,但Java会把这个所谓的构造器当成方法来处理,它就不再是构造器。
学生提问:构造器不是没有返回值吗?为什么不能用void声明呢?
答:简单地说,这是Java的语法规定。实际上,类的构造器是有返回值的,当使用new关键字来调用构造器时,构造器返回该类的实例, 可以把这个类的实例当成构造器的返回值,因此构造器的返回值类型总是当前类,无须定义返回值类型。但必须注意:不要在构造器里显式使用return来返回当前类的对象,因为构造器的返回值是隐式的。
java中对象和对象引用在内存中怎么存储?
引用在栈内存中,对象在堆内存中,当一个对象被创建成功以后,这个对象将保存在堆内存中,Java程序不允许直接访问堆内存中的对象,只能通过该对象的引用操作该对象。也就是说不管是数组还是对象,都只能通过引用来访问它们。
static关键字不能修饰构造器。
定义成员变量(field,也叫字段,域):
修饰符 类型 成员变量名 [=默认值],对定义成员变量语法格式的详细说明如下。
1.修饰符:可省略,也可以是public、protected、private、static、final,其中public、protected、private三个最多只能出现其中之一,可以与static、final组合起来修饰成员变量。
2.类型:类型可以是Java语言允许的任何数据类型,包括基本类型和现在介绍的引用类型。
3.成员变量名:只要是一个合法的标识符即可,实战中成员变量名应该由一个或多个有意义的单词连缀而成,第一个单词首字母小写,后面每个单词首字母大写,其他字母全部小写,单词与单词之间不要使用任何分隔符。成员变量用于描述类或对象包含的状态数据,因此成员变量名建议使用英文名词。
4.默认值:定义成员变量还可以指定一个可选的默认值。
定义方法(多了个修饰符abstract):
修饰符 返回值类型 方法名字(形参列表){},对定义方法语法格式的详细说明如下。
1.修饰符:修饰符可以省略,也可以是public,protected,private ,static,final,abstract,其中 public 、protected、private三个最多只能出现其中之一;abstract和final最多只能出现其中之一,它们可以与static组合起来修饰方法。
2.方法返回值类型:返回值类型可以是Java语言允许的任何数据类型,包括基本类型和引用类型;如果声明了方法返回值类型,则方法体内必须有一个有效的return语句,该语句返回一个变量或一个表达式,这个变量或者表达式的类型必须与此处声明的类型匹配。除此之外,如果一个方法没有返回值,则必须使用void来声明没有返回值。
3.方法名:方法名的命名规则与成员变量的命名规则基本相同,但由于方法用于描述该类或该类的实例的行为特征或功能实现,因此通常建议方法名以英文动词开头。
4.形参列表:形参列表用于定义该方法可以接受的参数,形参列表由零组到多组“参数类型 形参名”组合而成,多组参数之间以英文逗号(,)隔开,形参类型和形参名之间以英文空格隔开。一旦在定义方法时指定了形参列表,则调用该方法时必须传入对应的参数值——谁调用方法,谁负责为形参赋值。方法体里多条可执行性语句之间有严格的执行顺序,排在方法体前面的语句总是先执行,排在方法体后面的语句总是后执行。
static是一个特殊的关键字,它可用于修饰方法、成员变量等成员。static修饰的成员表明它属于这个类本身,而不属于该类的单个实例,因为通常把static修饰的成员变量和方法也称为类变量、类方法。不使用static修饰的普通方法、成员变量则属于该类的单个实例,而不属于该类。因为通常把不使用static修饰的成员变量和方法也称为实例变量、实例方法。
由于static的英文直译就是静态的意思,因此有时也把static修饰的成员变量和方法称为静态变量和静态方法,把不使用static修饰 的成员变量和方法称为非静态变量和非静态方法。静态成员不能直接访问非静态成员。
提示:
虽然绝大部分资料都喜欢把static称为静态,但实际上这种说法很模糊,完全无法说明static的真正作用。static的真正作用就是用于区分成员变量、方法、内部类、初始化块这四种成员到底属于类本身还是属于实例。在类中定义的成员,static相当于一个标志,有static修饰的成员属于类本身,没有static修饰的成员属于该类的实例。
补充知识点:
java对象的this:
this关键字总是指向调用该方法的对象。根据this出现位置的不同,this作为对象的默认引用有两种情形。
1.在构造器中引用该构造器正在初始化的对象。
2.在方法中引用调用该方法的对象。
this关键字最大的作用就是让类中一个方法,访问该类里的另一个方法或实例变量。this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的:它所代表的只能是当前类的实例;只有当这个方法被调用时,它所代表的对象才被确定下来:谁在调用这个方法,this就代表谁。
对于static修饰的方法而言,则可以使用类来直接调用该方法, 如果在static修饰的方法中使用this关键字,则这个关键字就无法指向合适的对象。所以,static修饰的方法中不能使用this引用。由于static修饰的方法不能使用this引用,所以static修饰的方法不能访问不使用static修饰的普通成员,因此Java语法规定:静态成员不能直接访问非静态成员。
提示:
省略this前缀只是一种假象,虽然程序员省略了调用jump()方 法之前的this,但实际上这个this依然是存在的。根据汉语语法习惯:完整的语句至少包括主语、谓语、宾语,在面向对象的世界里,主、谓、宾的结构完全成立,例如“猪八戒吃西瓜”是一条汉 语语句,转换为面向对象的语法,就可以写成“猪八戒.吃(西 瓜);”,因此本书常常把调用成员变量、方法的对象称为“主调 (主语调用者的简称)”。对于Java语言来说,调用成员变量、方法时,主调是必不可少的,即使代码中省略了主调,但实际的主调依然存在。一般来说,如果调用static修饰的成员(包括方法、成员变量)时省略了前面的主调,那么默认使用该类作为主调;如果调用没有static修饰的成员(包括方法、成员变量)时省略了前面的主调,那么默认使用this作为主调。如果确实需要在静态方法中访问另一个普通方法,则只能重新创建一个对象,极端情况下。
this引用也可以用于构造器中作为默认引用,由于构造器是直接使用new关键字来调用,而不是使用对象来调用的,所以this在构造器中代表该构造器正在初始化的对象。