Java面向对象(一) 类与对象以及方法
面向对象概述
- 面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。
- 在OOP中,不必关心对象的具体实现,只要能够满足用户的需求即可。
类
- 类是构造对象的模板或蓝图。
- Java编写的所有代码都位于某个类的内部。
- Java中的类文件时以.java为后缀的代码文件,在每个类文件中最多只允许出现一个public类。
- 当
有public类
时,类文件名
必须和public类的名称相同
。 - 当
没有public类
时,类文件名可以是任意合法名称
。
- 当
实例
- 由类构造对象的过程称为创建类的实例。
封装
- 封装也称为数据隐藏,是面向对象思想的三大特性之一。
- 从形式上看,封装不过是将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式。
- 实现封装的关键在于绝对不能让类中的方法直接地访问其他类的实例域。
- 程序也是仅仅通过对象的方法与对象的数据进行交互。
- 好处:
- 封装给对象赋予了“黑盒”特征,这是提高重用性和可靠性的关键。
- 一个类可以全面地改变存储数据的方式,只要仍旧使用同样的方法操作数据,其他对象就不会知道或介意所发生的变化。
对象
- 对象的三个主要特征:
- 对象的
行为
(behavior):可调用的方法
- 对象的
状态
(state):描述当前对象的特性信息
- 对象的
标识
(identity):进行辨别
具有相同行为与状态
的不同对象
- 对象的
- 对象中的
数据
称为实例域
,操纵数据
的过程称为方法
。 - 对于
每个特定的类实例
(对象)都有一组特定的实例域值
。这些值的集合就是这个对象的当前状态
(state)。 - 无论何时,只要对象发送一个消息,它的状态就有可能发生改变。
- 对象的
状态的改变必须通过调用方法实现
,不会自发改变
。如果不经过方法调用就可以改变对象状态,只能说明封装性遭到了破坏。 - 对象的状态并不能完全描述一个对象,每个对象都有一个唯一的身份标识。
- 作为一个类的实例,每个对象的标识永远是不同的,状态也常常存在差异。
对象变量
- 一个
对象变量
并没有实际包含一个对象
,而仅仅引用
一个对象 - Java中,任何
对象变量
的值
都是对存储在另外一个地方的一个对象的引用
。new
操作符的返回值
也是一个引用
,这个返回值引用存储在对象变量
中。 - Java中,局部变量不会自动初始化为null,而必须通过调用new或者将他们设置为null进行初始化。
成员变量初始化
- 在Java类内部,对于
成员变量
,如果在定义时没有
直接进行赋值初始化
,那么Java会保证
类的每个成员变量都得到对应的初始化值
。- 对于
基本类型
变量,char short byte int long float double 等都会默认初始化为0
,boolean类型
变量值默认会被初始化为false
。 - 对于
引用类型
的变量,会默认初始化为null
- 对于
方法(行为)
方法重载
- 方法名相同,与返回值类型无关,只看参数列表
构造器
- 构造器概述和作用:
- 给对象的数据(实例域)进行初始化
- 构造器规则:
- 构造器
必须与类同名
- 每个类可
以有一个或者多个构造器
(构造方法的重载) - 构造器
可以有0个、1个或者多个参数
(构造方法的重载) - 构造器
没有返回类型
,连void都没有
- 构造器
没有返回值
,但是默认会有return;
,可以省略 - 构造器
总是伴随着null操作符一起调用
- 构造器
- 注意点:
不要在构造器中定义与实例域重名的局部变量
- 构造方法
不能使用该类的对象调用
,即:p.Person()
是错误
的 - 如果我们自身没有给出构造方法, 系统将
自动
提供一个无参构造方法
。 - 如果我们给出了构造方法,系统将不再提供默认的无参构造方法。
- 建议永远自己给出无参构造方法。
访问器方法
在类中,例如
getXxx()
方法,用于获取实例域值(属性值)的方法
称为访问器。可以自定义改变内部实现
,除了该类的方法之外,不会影响其他代码
为什么不直接让属性使用public修饰,直接获取?
如果使用
public
进行修饰,就破坏了封装的思想
,那么破坏这个属性值的有可能会出现在任何地方
。属性在类中进行
封装
,它是一个只读域
,一旦在构造器
中设置
完毕,就没有任何一个办法可以对其进行修改
,从而来确保属性不会受外界的破坏
。
更改器方法
- 在类中,例如
setXxx()
方法,用于更改实例域值
(属性值)的方法 - 为了
进行新旧数据之间的转换
- 可以执行错误检查,然而直接对域进行赋值将不会进行这些处理
- 一个私有的数据实例域
- 一个公有的域访问器方法
- 一个公有的域更改器方法
可变对象注意点
注意: 不要编写返回引用可变对象的访问器方法!
一个Date类的实例:Date类中本身有一个更改器方法
setTime
可以设置毫秒数,此时的Date对象是可变的,破坏了封装性,就会发生数据不一致。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class DateTest {
public static void main(String[] args) {
Student student = new Student(new GregorianCalendar().getTime());
Date d = student.getDay();
System.out.println(student.getDay()); //Thu Jul 19 11:15:02 CST 2018
//Date对象d内部提供了一个方法 可以设置时间
d.setTime(d.getTime()-(long)10*365*24*3600*1000);
//虽然没有使用Student对象设置时间,最后还是回到了10年前
//说明该Student类中的Date对象属性可以被除了Student本身的对象方法改变,存在了数据安全隐患
//破坏了封装性
System.out.println(student.getDay()); //Mon Jul 21 11:15:02 CST 2008
}
}
class Student {
private Date day;
public Student(Date day){
this.day = day;
}
public Date getDay(){
return day;
}
}上述代码执行结果:
1
2Thu Jul 19 11:15:02 CST 2018
Mon Jul 21 11:15:02 CST 2008由此发现:
- 虽然没有使用Student对象设置时间,最后还是回到了10年前,说明该Student类中的Date对象属性可以被
除了Student本身的对象的方法改变
,存在了数据安全隐患,破坏了封装性 - 如果实在是需要返回一个可变对象的引用,应该对它进行克隆。
- 对象clone是指在另一个位置存放一个对象副本。
更改访问器代码:
1
2
3
4public Date getDay(){
//由于Date类对象是一个可变对象,所以应使用clone,保证数据不被外界修改
return (Date) day.clone();
}- 虽然没有使用Student对象设置时间,最后还是回到了10年前,说明该Student类中的Date对象属性可以被
给成员变量赋值的两种方式
- 使用更改器修改属性值:
setXxx()
方法 - 使用构造器,给对象初始化属性值
隐式参数与显式参数
- 隐式参数
- 出现在方法名前的类对象
- Java中常常使用
this
关键字表示
- 显式参数
- 位于方法名后面括号中的数值,明显地列在方法声明中
main方法
- 在Java中,main方法是Java程序的入口,Java核心编程中,
JVM
会查找类中的public static void mian(String[] args)
,如果找不到该方法
就会抛出错误NoSuchMethodError:main
程序终止。 - main 方法必须严格遵循它的语法规则,即它的方法签名必须是
public static void
,方法名必须是main
,参数是字符串数组类型
,参数名可以随意更改。Jdk1.5以后还可以使用可变参数:public static void main(String... args)
main方法的规则
- 必须是static的
- 因为需要被JVM调用,不用创建对象实例,直接类加载就可以访问。
- 需要JVM的调用,因为main方法是静态的,JVM调用这个方法时就
不需要创建包含这个main方法的类的实例
。 - 反之,如果不是静态的,JVM就必须需要创建包含这个main方法的类的实例, 因为
构造器可以被重载,JVM就没法确定调用哪个main方法
。
- 需要JVM的调用,因为main方法是静态的,JVM调用这个方法时就
- 因为需要被JVM调用,不用创建对象实例,直接类加载就可以访问。
- 必须是
public
修饰- 因为需要被JVM调用,权限为public就可以轻松的访问执行它。
- 必须是void类型的
- 因为被JVM调用,
不需要
有任何的返回值
- 因为被JVM调用,
- 方法名必须是main
- 因为只有方法名是main,JVM才会
识别
,注意main不是一个关键字。
- 因为只有方法名是main,JVM才会
- 参数必须是
String[]数组类型
或者String... 可变参数类型
- 除了
static
void
public
,还可以使用final
synchronized
和strictfp
关键字就行修饰main方法 main
方法可以
像其他方法一样被重载
,但是JVM还是
会调用上面这种签名规范的main方法。- 可以使用
throws
子句在main方法中,可以抛出
任何checked和unchecked异常。 静态域
在JVM调用main方法之前
就初始化了,它们在类被JVM加载到内存是就执行了。