Java——面向对象——基础
概述
对象,就是指客观存在的事物,万物皆对象。
- 客观存在的任何一种事物,都可以看作为程序中的对象
- 使用面向对象思想可以将复杂的问题简单化
- 将我们从执行者的位置,变成了指挥者
面向对象和面向过程的思想对比
面向过程编程
是一种以过程为中心的编程思想,实现功能的每一步,都是自己实现的。
面向对象编程
是一种以对象为中心的编程思想,通过指挥对象实现具体的功能。
什么是类
类是对现实生活中一类具有共同属性和行为的事物的抽象。简单的理解的就是类是对事物,也就是对象的一种描述,可以将类理解为一张设计图,可以根据设计图,创造出具体存在的事物。
可以根据类创造对象。
类的组成
- 属性:该事物的各种特征,例如学生事物的属性,姓名、年龄毕业院校...
- 行为:该事物存在的功能,就是能够做的事情,例如学生的行为,学习、Java开发编程。
类和对象的关系
- 类:是对现实生活中一类具有共同属性和行为的事物的抽象,类就是对象的描述
- 对象:是能够看得到摸得着的真实存在的实体,对象就是类的实体
类的定义
说明
类的组成是属性和行为,属性在代码中可以通过成员变量(类中方法外的变量)来体现。行为在代码中可以通过成员方法来体现,和普通方法类似,去掉关键字static即可。
步骤
定义类 ——》 定义类的成员变量 ——》编写类的成员方法
代码实现如下
public class 类名 {
// 成员变量
变量1的数据类型 变量1;
变量2的数据类型 变量2;
...
// 成员方法
方法1;
方法2;
...
}
比如创建一个Student学生类,学生类的成员变量有姓名(name)、年龄(age),成员方法有学习(study),如下
// 属性 姓名、年龄
// 成员变量 跟定义普通对象的格式一样,只不过位置发生了改变,类中方法外
String name;
int age;
// 行为 学习
// 成员方法 跟普通定义方法的格式一样,去掉了static关键字
public void study(){
System.out.println("学习");
}
这样,一个基本的类就定义好了。
对象的创建
参照已经定义好的类,我们可以在测试类中来创建对象,格式如下
类名 对象名 = new 类名();
例子
Student stu = new Student();
对象的使用
在测试类中使用对象的格式如下
// 使用成员变量 对象名.对象名 // 使用成员方法 对象名.方法名()
例子
System.out.println(stu.age); // 0 stu.study(); // 学习
这里需要注意的是,即使我们没有给对象的属性赋值,也还是可以拿到具体的值,这里叫做默认初始化值,不会编译出错,比如String 为 null, int 为 0。
也可以对属性进行赋值操作,如下
stu.name = "张三"; stu.age = 27; System.out.println(stu.name); // 张三 System.out.println(stu.age); // 27
对象的内存存储
有如下俩个类,一个Student类,一个TestStudent测试类
Student
public class Student {
String name;
int age;
public void study(){
System.out.println("学习");
}
}
TestStudent
public class TestStudent {
public static void main(String[] args) {
Student stu = new Student();
System.out.println(stu.age); // 0
stu.name = "张三";
stu.age = 27;
System.out.println(stu.name); // 张三
System.out.println(stu.age); // 27
stu.study(); // 学习
}
}
首先拥有主方法的测试类的字节码文件(TestStudent.class)加载进方法区,目前这个字节码文件中只有一个主方法main,主方法被虚拟机自动调用执行,进入到栈内存,第一句代码Student = stu...就是声明了一个对象类型的变量,由于内存中没有Student这个类,所以系统这一步也会把Student这个类的字节码文件(Student.class)加载进方法区,加载进来之后,成员变量和成员方法在方法区都是存在的,加载进来之后,继续 new Student(),有new就会进堆,自动在堆内存中开辟空间,产生地址,由于对象是根据类来创建的,所以类中存在的成员变量在堆内存当中也同时存在着这么一份,堆内存中的数据都有自己的默认初始化值,所以name,age都有了自己的默认初始化值,null和0,此时,成员方法是不会进入堆内存的,但是,堆内存中是会有那么一块地址是用于存在方法的引用地址的,将来可以通过这个地址找到方法区中的成员方法,此时就可以把堆内存中的地址赋值给stu了,所以如果此时打印stu,打印的就是地址值,接下来打印成员变量,就可以通过地址值找到堆内存中的这块内存,也可以根据name和age继续找到成员变量的值,null和0,并且改变它们。调用study方法是通过stu找到堆内存中的这块地址,然后再通过保存过的这个地址,找到方法区中的字节码文件的study方法,找到之后,把study方法加载进栈内存当中运行,执行完study里面的功能之后,就会从栈内存中弹栈消失。由于study()是主方法中的最后一句代码,study调用完毕之后,主方法也会从栈内存当中弹栈消失。至此,程序执行完毕。
注意
如果再次创建Student对象,是不会再次Student这个类的字节码文件(Student.class)加载进方法区的。
俩个引用指向同一个对象
情况如下,有俩个类
Student
public class Student {
String name;
int age;
public void study(){
System.out.println("学习");
}
}
TestStudent
public class TestStudent {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.name = "张三";
Student stu2 = stu1;
stu2.name = "李四";
System.out.println(stu1.name + "------" + stu2.name); // 李四------李四
}
}
由于俩个引用指向了同一个内存空间,所以只要一个改变了对象,俩个再次取值看到的就是改动之后的结果了。
这里我可以把对象变量赋值为null来断开连接,如下:
stu1 = null; System.out.println(stu1.name); // NullPointerException(空指针异常)
如果设为null之后,再次通过stu1取属性值,就会提示空指针异常。此时不会影响另一个引用(stu2),我们还是可以通过stu2找到堆内存中的这块地址,如下
stu1 = null; // System.out.println(stu1.name); // NullPointerException(空指针异常) System.out.println(stu2.name); // 李四
如果之后又将stu2赋值为null,此时就没有引用能够找到堆内存中的这块地址内容了,这块内容就成了内存中的垃圾对象,垃圾对象会被Java的垃圾回收器在空闲的时候,自动进行清理。下面有描述。
垃圾回收
当堆内存中,对象或数组产生的地址,通过任何方式都不能被找到后,就会被判定为内存中的"垃圾","垃圾"会被Java垃圾回收器,空闲的时候,自动清理。有部分语言,"垃圾"是需要程序员手动清理的。
成员变量和局部变量
- 成员变量——就是类中方法外的变量,判断一个变量是不是成员变量,就看它是不是类中方法外的变量,就就可以了
- 局部变量——就是方法当中的变量
public class Student {
String name;
int age;
public void study(){
int i = 0;
System.out.println("学习");
}
}
上面代码,name 和 age 就是成员变量,study方法中的 i 就是局部变量。
成员变量和局部变量有如下区别
| 区别 | 成员变量 | 局部变量 |
| 类中位置不同 | 类中方法外 | 方法内或者方法声明上(形参) |
| 内存中位置不同 | 堆内存 | 栈内存 |
| 生命周期不同 | 随着对象的存在而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的调用完毕消失 |
| 初始化值不同 | 有默认的初始值 | 么有默认的初始化值,必须先定义,赋值,才能使用 |
封装
private
private是一个访问修饰符,这个单词的意思是私有的,它的作用可以用来修饰成员(变量和方法)。被它修饰过的成员,只能在本类中进行访问。如下
public class Student {
private String name;
int age;
public void show(){
System.out.println(name + "-----" + age);
}
}
上面Student类中的name成员变量就被private修饰符修饰过了。这样的话,其他的类就无法访问它了。
public class TestStudent {
public static void main(String[] args) {
Student stu = new Student();
stu.name = "张三"; // name在com.baidu.Student中是private访问控制
}
}
使用访问修饰符修饰成员就是可以提高了数据的安全性,如果使用private,还需要提供如下的操作
- 提供"get变量名()"方法,用于获取成员变量的值,方法用public修饰
- 提供"set变量名(参数)"方法,用于设置成员变量的值,方法用public的值
public class Student {
private String name;
private int age;
public String getName(){
return name;
}
public void setName(String n){
name = n;
}
public int getAge(){
return age;
}
public void setAge(int a){
age = a;
}
public void show(){
System.out.println(name + "-----" + age);
}
}
如此使用的直观影响就是在其他类中是无法通过"对象.变量名"的方式获取和修改成员变量了,但是也提高了安全性,比如用户在设置年龄的时候,我们在设置年龄的方法中(setAge),加以判断,必须在某个范围内,才能设置成功。如下
// Student.java
public void setAge(int a){
if(a >= 0 && a <= 120){
age = a;
}else{
System.out.println("您设置的年龄有误");
}
}
// TestStudent.java
Student stu = new Student();
stu.setAge(130); // 您设置的年龄有误
总结:今天在定义成员变量时,都需要采用private修饰。再提供get、set方法,从而提高代码的安全性。
this
在Java中,当成员变量和局部变量重名时,Java会采用就近原则,如下
// Student.java
public class Student {
private int age = 10;
public void show() {
int age = 20;
System.out.println(age);
}
}
// ThisTest01.java
public class ThisTest01 {
public static void main(String[] args) {
Student stu = new Student();
stu.show(); // 20
}
}
这时,如果需要访问打印成员变量age,而不是局部变量age,就可以加上this关键字,如下
// Student .java
public class Student {
private int age = 10;
public void show() {
int age = 20;
System.out.println(this.age);
}
}
// ThisTest01.java
public class ThisTest01 {
public static void main(String[] args) {
Student stu = new Student();
stu.show(); // 10
}
}
所以,this关键字的作用就是可以调用本类的成员(变量、方法),解决成员变量和局部变量的重名问题。
this代表所在类的引用,方法被哪个对象调用,this就代表哪个对象。
构造方法
构造方法就是构建、创造对象的时候,所调用的方法。
它的作用就是用于给对象的数据(属性)进行初始化。
构造方法的书写格式有如下特点
- 方法名与类名相同,大小写也要一致
- 没有返回值类型,连void都没有
- 没有具体的返回值,不能由return带回结果数据
- 创建对象的时候调用,每创建一次对象,不能手动调用
以下就是一个最简单的构造方法
// Student.java
public class Student {
public Student(){
System.out.println("我是Student类的构造方法");
}
}
// TestStudent.java
public class TestStudent {
public static void main(String[] args) {
Student stu = new Student(); // 我是Student类的构造方法
}
}
根据Student类创建出来对象的时候,就会执行Student类的构造方法。
因为构造方法在创建对象的时候会自动调用一次,所以,我们可以让它额外帮我们初始化一下成员变量,如下就是构造方法的标准使用
// 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 String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// TestStudent.java
public class TestStudent {
public static void main(String[] args) {
Student stu = new Student("张三",27);
System.out.println(stu.getName() + "——" + stu.getAge()); // 张三——27
}
}
上面代码提供了一个空参构造方法和一个有参构造方法,这样我们我们创建类的时候就可以看情况初始化对象的属性。
构造方法也有一些注意事项,如下
- 如果没有定义构造方法,系统将会给出一个默认的无参构造方法
- 如果定义了构造方法,系统将不再提供默认的构造方法
- 如果自定义了带参构造方法,还要使用无参构造方法,就必须再写一个无参数 构造方法
- 还是建议今后无论是否使用,都手动书写无参数构造方法和带参数构造方法
JavaBean类
上面用于封装数据的Student类就称为JavaBean类。

浙公网安备 33010602011771号