面向对象(五)


面向对象(五)

面向对象编程就是拿东西来做对应的事,就比如人要洗衣服会拿洗衣机洗。

类和对象

:是对象共同特征的描述。
对象:是真实存在的具体东西。
在java中,必须先设计类,才能获得对象。
类是对象的抽象,对象是类的实例。

类的定义:

1
2
3
4
5
6
7
public class 类名{
1.成员变量(代表属性,一般是名词)
2.成员方法(代表动作,一般是动词)
3.构造器
4.代码块
5.内部类
}

类的对象

1
类名 对象名 = new 类名();

类的使用

访问属性
对象名.成员变量
访问行为:
对象名.方法名(……)

定义类的注意事项

类名首字母建议大写,见名知意,驼峰模式。
一个java文件可定义多个class类,但只能一个类是public修饰,public修饰的类名必须成为代码文件名。
实际开发中建议一个文件定义一个class类。
成员变量的完整定义格式:
修饰符 数据类型 变量名称=初始值;
一般无需指定初始化值,存在默认值
用来描述一类事物的类,叫做:javabean类。在javabean类中,是不写main方法的。
编写main方法的类,叫做测试类。可以在测试类中创建javabean类的对象并进行复制调用

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
//javabean类
//Student.java
public class Student{
String name;
String sex;
int grade;
public void play(){
System.out.println(name+"在玩");
}
public void study(){
System.out.println(name+"在学习");
}
}
1
2
3
4
5
6
7
8
9
10
11
//测试类
public class StudentTest{
public static void main(String[] args){
Student student=new Student();
student.name="张三";
student.sex="男";
student.grade=60;
student.play();
student.study();
}
}

封装

封装便是告诉我们,如何正确设计对象的属性和方法。
对象代表什么,就要封装相应的数据,并提供数据相应的行为。

private关键字

private是一个权限修饰符,可以修饰成员(成员变量和成员方法),被private修饰的成员只能在本类中才能访问。
针对private修饰的成员变量,若需被其他类使用,要提高响应的操作。
提供”setXXX(参数)”方法,用于给成员变量赋值,方法用public修饰。
提供”getXXX()”方法,用于获取成员变量的值,方法用public修饰。
:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Student.java
public class Student{
private String name;
private String sex;
private int grade;
public void setName(String n){
name=n;
}
public String getName(){
return name;
}
public void setSex(String s){
sex=s;
}
public String getSex(){
return sex;
}
public void setGrade(int g){
if(g>=0 && g<=100){
grade=g;
}else{
System.out.println("参数非法");
}
}
public int getGrade(){
return grade;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
//StudentTest.java
public class StudentTest{
public static void main(String[] args){
Student student=new Student();
student.setName("zhangsan");
student.setSex("男");
student.setGrade(56);
System.out.println(student.getName());
System.out.println(student.getSex());
System.out.println(student.getGrade());
}
}

this关键字

当成员变量和局部变量重名时,就会触发就近原则(谁离我近,我就用谁)
this可以区别成员变量和局部变量。
this的本质:代表所在方法调用者的地址值

1
2
3
4
5
6
7
8
9
10
public class Student{
private int age;//成员变量
public void method(int age){
int age=10;//局部变量
System.out.println(age);
//触发就近原则,打印局部变量age,10
System.out.println(this.age);
//此时age是成员变量
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Student.java
public class Student{
private String name;
private String sex;
private int grade;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setSex(String sex){
this.sex=sex;
}
public String getSex(){
return sex;
}
public void setGrade(int grade){
if(grade>=0 && grade<=100){
this.grade=grade;
}else{
System.out.println("参数非法");
}
}
public int getGrade(){
return grade;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//StudentTest.java
public class StudentTest{
public static void main(String[] args){
Student student=new Student();
//this代表的是student的地址值
student.setName("zhangsan");
//this.name=name;
//等号右边name遵循就近原则,为形参,接收zhangsan
//等号左边this为student的地址值,取的成员变量name
student.setSex("男");
student.setGrade(56);
System.out.println(student.getName());
System.out.println(student.getSex());
System.out.println(student.getGrade());
}
}

构造方法

构造方法也就做构造器,构造函数。
作用:在创建对象时给成员变量进行赋值。
分类无参数构造方法有参数构造方法

格式

1
2
3
4
5
6
7
8
9
10
11
public class 类名{
//空参构造方法
修饰符 类名(){
方法体
}

//带全部参数构造方法
修饰符 类名(参数){
方法体;
}
}

特点

  • 方法名与类名相同,大小写也一致
  • 无返回值类型,也没有void
  • 也不能由return带回结果数据

执行时机

  • 创建对象时由虚拟机调用,不能手动调用构造方法
  • 每创建一次对象,就会调用一次构造方法。

注意事项

  1. 构造方法的定义
    • 若未定义构造方法,系统将给出一个默认的无参数构造方法
    • 若定义了构造方法,系统不再给出默认的无参数构造方法
  2. 构造方法的重载
    • 带参和无参构造方法,两者方法名相同,参数不同,称为构造方法的重载
  3. 无论是否使用,都尽量写无参和带参的构造方法

范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//javabean类
//Student.java
public class Student{
private String name;
private int age;
//无参构造方法
public Student(){

}
//带参构造方法
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
1
2
3
4
5
6
7
8
9
//测试类
//StudentTest.java
public class StudentTest{
public static void main(String[] args){
Student student=new Student("zhangsan",16);
System.out.println(student.getName());
System.out.println(student.getAge());
}
}

标准的javabean类

  • 类名需见名知意。
  • 成员变量使用private修饰
  • 提供至少两种构造方法
    • 无参构造方法
    • 带全部参数构造方法
  • 成员方法
    • 提供每一个成员变量的对应的setXXX()/getXXX()
    • 若有其他行为,也写上

成员变量和局部变量的区别

  • 类中位置不同:
    • 成员变量在类中,方法外
    • 局部变量在方法内,方法声明上
  • 初始化值不同:
    • 成员变量有默认初始化值
    • 局部变量没有
  • 内存位置不同:
    • 成员变量在堆内存
    • 局部变量在栈内存
  • 生命周期不同:
    • 成员变量随着对象创建而存在,随着对象消失而消失
    • 局部变量随着方法的调用而存在,随着方法的运行结束而消失
  • 作用域不同
    • 整个类中有效
    • 当前方法有效

对象内存

在创建对象时系统最少会做七件事

  1. 加载class文件
  2. 申明局部变量
  3. 在堆内存中开辟一个空间
  4. 默认初始化
  5. 显示初始化
  6. 构造方法初始化
  7. 将堆内存中的地址值赋值给左边的局部变量

创建一个对象

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//javabean类
//Student.java
public class Student{
private String name;
private int age;
//无参构造方法
public Student(){

}
//带参构造方法
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
1
2
3
4
5
6
7
//测试类
//StudentTest.java
public class StudentTest{
public static void main(String[] args){
Student student=new Student();
}
}

字节码文件:.java源文件经过编译生成的.class便是字节码文件,但还不能被系统直接执行,通过JVM解释翻译后才可以被底层系统执行。

首先StudentTest.java的字节码文件加载到方法区,main方法在方法区临时存储。随后,虚拟机自动调用程序的主入口main方法,main方法会被压入栈内,然后利用代码 Student student=new Student(“zhangsan”,16);创建对象student,执行上述的七步,具体为:

  1. 加载class文件:
    • 将Student.java加载到方法区,包括其中所有成员变量和方法
  2. 申明局部变量
    • Student student=new Student();执行“=”左边的代码,在栈内存的main方法中创建变量student,student能够存储Student类对象的地址值
  3. 在堆内存中开辟一个空间
    • Student student=new Student();执行“=”右边的代码。会将所有类中的成员变量和成员方法的地址值存储到堆内存
  4. 默认初始化
    • 将成员变量初始化。name为null,age为0
  5. 显示初始化
    • 若在定义成员变量时直接赋值(比如priavte String name=”zhangsan”;private int age=15;)这就叫做显示初始化,不过范例中并未初始化,所以这步可忽略
  6. 构造方法初始化
    • 范例中是空参构造,可以忽略;若是有参构造创建对象,name和age便会被赋值
  7. 将堆内存中的地址值赋值给左边的局部变量
    • Student student=new Student();将右边代码在堆中创建的对象的地址赋给student

:当main方法执行完毕,便会出栈,出栈后main方法的所有变量都会被释放,其中包括存储对象地址的变量,即范例中student变量被释放,若没有变量指向对象在堆内存中所处的空间,该空间便会消失。

多个对象

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//javabean类
//Student.java
public class Student{
private String name;
private int age;
//无参构造方法
public Student(){

}
//带参构造方法
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
1
2
3
4
5
6
7
8
//测试类
//StudentTest.java
public class StudentTest{
public static void main(String[] args){
Student student1=new Student();
Student student2=new Student();
}
}

student1创建步骤与上面创建单个对象的步骤大致相同。
student2不需要再次加载class文件,相对于student少了一步,而其他步骤与创建student1大致相同

多个引用指向同一对象

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//javabean类
//Student.java
public class Student{
private String name;
private int age;
//无参构造方法
public Student(){

}
//带参构造方法
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//测试类
//StudentTest.java
public class StudentTest{
public static void main(String[] args){
Student student1=new Student();
Student student2=student1;
student1.setName("ljs");
student1.setAge(15);
System.out.println(student1.getName());
System.out.println(student2.getName());
System.out.println(student1.getAge());
System.out.println(student2.getAge());
student2.setName("sjl");
student2.setAge(16);
System.out.println("==============");
System.out.println(student1.getName());
System.out.println(student2.getName());
System.out.println(student1.getAge());
System.out.println(student2.getAge());
}
}
/*
ljs
ljs
15
15
==============
sjl
sjl
16
16
*/

创建student1对象的步骤与创建单个对象的步骤大致相同,student2被赋值了student1存储的对象地址,student1和student2的存储的对象地址相同,也就是这两个变量指向同一个对象的地址,所以当其中一个对象的成员变量被改变,另一个也会跟着改变,比如student1.name改为sjl,student1.age被改为16,则student2.name和student2.age也会发生改变,变为sjl和16。
当student1和student2都不再存储对象在堆内存中所处的地址时,该对象会消失。


Author: ljs
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source ljs !
评论
  TOC