面向对象介绍
面向对象的概念
- 面向:拿、取
- 对象:能干活的东西
- 面向对象就是拿对应的东西来做相应的事情
面向对象抽象理解
- 洗衣服用到洗衣机、扫地用到扫地机器人
- 因此会更方便
JAVA中的面向对象在哪里体现?
- 若想生成一个随机数,我们会使用random
- 若想输入,我们会使用scanner
- ......
面向对象需要掌握的两个点
- 一个是如何使用相应的工具
- 另一个是学习如何设计自己想要的工具
类和对象
基本介绍
- 类:是对象共同特征的描述(可以理解为是对象的设计图)
- 对象:是一个具体存在的东西
因此若是想使用一个对象,则需要设计好一个类
- 设计一个手机的类
package com.itheima.test;
public class Phone {
// 属性
String brand;
double price;
// 行为
public void call() {
System.out.println("手机在打电话");
}
public void playgame() {
System.out.println("手机在玩游戏");
}
}
- 创建一个手机的对象并赋上初值
package com.itheima.test;
public class PhoneTest {
public static void main(String[] args) {
// 创建手机的对象
Phone p = new Phone();
p.brand = "小米";
p.price = 1999.99;
System.out.println(p.brand);
System.out.println(p.price);
p.call();
p.playgame();
}
}
- 运行结果
定义类的补充注意事项
- 用来描述一类事物的类,专业叫做:javabean类
- javabean类中不写main方法
- 编写main方法的类称为测试类
- 可以在测试类中调用javabean类的对象进行赋值使用
- 类名的首字母建议是大写的,并且类名需要见名知意
- 一个java文件可以定义多个class类,但只能有一个类是public修饰的,并且public修饰的类名需要与该java文件的文件名相同
- 在一个java文件中定义多个class类并没有意义,所以实际开发中一个java文件中只定义一个class类
- 成员变量的定义格式:修饰符 数据类型 变量名 = 初始化值; 但一般不需要定义初始值,存在默认值,一般在测试类中创建类的对象后再进行赋值
对象成员变量的默认值规则
封装
- 封装可以让我们知道如何正确设计一个属性和方法
- 例如人画圆,画圆这一行为是要写在圆这一个类中
- 人关门,关门这一行为也是要写在门这一个类中
- 而不是写在人这一个类中
封装的好处
- 对象代表什么,就得封装对应的数据,并提供数据对应的行为
- 降低学习成本,可以少学、少记,有需要的时候再去寻找对应的方法
private关键字
- private关键字是一个权限修饰符
- 可以修饰成员变量和成员方法
- 被private修饰的成员变量和成员方法只能在本类当中访问
- 针对private修饰的成员变量,如果其他类想要调用,需要提供对应的操作
- 提供“setXxx(参数)”方法,用于给成员变量赋值,方法用public修饰
- 提供“getXxx(参数)”方法,用于获取成员变量的值,方法用public修饰
package com.itheima.test2;
public class GirlFriend {
// 属性
private String name;
private int age;
private String gender;
// 针对于每一个私有化的成员变量,都要提供set和get方法
// set方法:给成员变量赋值
// get方法:对外提供成员变量的值
// 作用:给成员变量name赋值
public void setName(String n) {
name = n;
}
// 作用:对外提供name属性值
public String getName() {
return name;
}
public void setAge(int a) {
if (a >= 18 && a<= 50) {
age = a;
}
else
System.out.println("非法字符");
}
public int getAge() {
return age;
}
public void setGender(String g) {
gender = g;
}
public String getGender() {
return gender;
}
// 行为
public void sleep() {
System.out.println("女朋友在睡觉");
}
public void eat() {
System.out.println("女朋友在吃饭");
}
}
package com.itheima.test2;
public class GirlFriendTest {
public static void main(String[] args) {
// 创建对象
GirlFriend girl = new GirlFriend();
// 赋值
girl.setName("黑马");
girl.setAge(18);
girl.setGender("女");
System.out.println(girl.getName());
System.out.println(girl.getAge());
System.out.println(girl.getGender());
// 调用方法
girl.eat();
girl.sleep();
}
}
- 这样操作的时候,如果年龄的赋值是错误的,比如用户提供的是负数的形式,就能够判断出来
- 这种判断实在类当中实现的,而不是在测试类当中实现的,更加的方便
this关键字
- 一般来说,在成员变量和局部变量重名的时候,调用这一变量则是依靠就近原则
- this的作用:区别成员变量和局部变量
package com.itheima.test3;
public class GirlFriend {
private int age;
public void method() {
int age = 10;
System.out.println(age); // 相同变量的取最近的值
System.out.println(this.age); // 有this则是取成员变量的值
}
}
package com.itheima.test3;
public class GirlFriendTest {
public static void main(String[] args) {
GirlFriend girl = new GirlFriend();
girl.method();
}
}
运行结果:
- 由于变量的取名原则,变量名最好是见名知意
- 因此在类中给私有的成员变量赋值的方法中,就需要this这一关键字的帮助
修改后的如下:
package com.itheima.test2;
public class GirlFriend {
// 属性
private String name;
private int age;
private String gender;
// 针对于每一个私有化的成员变量,都要提供set和get方法
// set方法:给成员变量赋值
// get方法:对外提供成员变量的值
// 作用:给成员变量name赋值
public void setName(String name) {
this.name = name;
// 等号右边的name是局部变量,遵循就近原则,是测试类中调用方法传递过来的数据
// 等号左边的name是成员变量
}
// 作用:对外提供name属性值
public String getName() {
return name;
}
public void setAge(int age) {
if (age >= 18 && age<= 50) {
this.age = age;
// 等号右边的age是局部变量,遵循就近原则,是测试类中调用方法传递过来的数据
// 等号左边的age是成员变量
}
else
System.out.println("非法字符");
}
public int getAge() {
return age;
}
public void setGender(String gender) {
this.gender = gender;
// 等号右边的gender是局部变量,遵循就近原则,是测试类中调用方法传递过来的数据
// 等号左边的gender是成员变量
}
public String getGender() {
return gender;
}
// 行为
public void sleep() {
System.out.println("女朋友在睡觉");
}
public void eat() {
System.out.println("女朋友在吃饭");
}
}
构造方法
构造方法概述
- 构造方法又称为构造函数、构造器
- 作用:在创建对象的时候给成员变量进行赋值
public class Student {
修饰符 类名(参数) {
方法体;
}
}
public class Student {
private String name;
private int age;
public Student() {
... // 空参构造
}
public Student(String name, int age) {
... // 带参构造
}
}
特点:
- 构造方法的名字需要与类名相同,大小写也需要一致
- 没有返回值类型,连void都不需要写
- 没有具体的返回值,因此不需要写return
执行时机:
- 创建对象的时候由虚拟机调用,不能手动调用构造方法
- 每创建一次对象,都会自行调用一次构造方法
构造方法注意事项
- 构造方法的定义
- 如果没有定义构造方法,系统将给出一个默认的无参构造方法
- 如果定义了构造方法,系统将不再提供默认的构造方法,则此时就没有默认的无参构造方法,若仍需要调用无参构造方法,则需要自己手写无参构造方法了
- 构造方法的重载
- 带参构造方法和无参构造方法,两者方法名相同,但参数不同,这个叫做构造方法的重载
- 推荐使用方法:
- 无论是否使用,都需要手写无参构造方法和带全部参数的构造方法
package com.itheima.test4;
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;
}
}
package com.itheima.test4;
public class StudentTest {
public static void main(String[] args) {
Student s = new Student("黑马", 18);
System.out.println(s.getName());
System.out.println(s.getAge());
}
}
标准的JavaBean类
- 类名需要见名知意
- 成员变量使用private修饰
- 提供至少两种构造方法
- 无参构造方法
- 带全部参数的构造方法
- 成员方法
- 提供每一个成员变量对应的setXxx()/getXxx()
- 如果还有其他行为,也需要写上
- 编写标准JavaBean类有快捷方法
-
// 快捷键 // alt + insert // alt + Fn + insert // 右键 --> Ptg To JavaBean
-
- 标准JavaBean类的格式示例
-
package com.itheima.test5; public class User { // 属性 private String username; private String password; private String email; private String gender; private int age; // 快捷键 // alt + insert // alt + Fn + insert // 右键 --> Ptg To JavaBean public User() { } public User(String username, String password, String email, String gender, int age) { this.username = username; this.password = password; this.email = email; this.gender = gender; this.age = age; } /** * 获取 * @return username */ public String getUsername() { return username; } /** * 设置 * @param username */ public void setUsername(String username) { this.username = username; } /** * 获取 * @return password */ public String getPassword() { return password; } /** * 设置 * @param password */ public void setPassword(String password) { this.password = password; } /** * 获取 * @return email */ public String getEmail() { return email; } /** * 设置 * @param email */ public void setEmail(String email) { this.email = email; } /** * 获取 * @return gender */ public String getGender() { return gender; } /** * 设置 * @param gender */ public void setGender(String gender) { this.gender = gender; } /** * 获取 * @return age */ public int getAge() { return age; } /** * 设置 * @param age */ public void setAge(int age) { this.age = age; } public String toString() { return "User{username = " + username + ", password = " + password + ", email = " + email + ", gender = " + gender + ", age = " + age + "}"; } }
-
三种情况的对象内存图
一个对象的内存图
两个对象的内存图
- 相比于一个对象,区别就在于不需要重新在方法区加载.class文件
两个引用指向同一个对象
- 在方法区加载.class文件,然后在栈内存中存储变量,堆内存在使用new()方法后开辟空间并存储地址。
基本数据类型和引用数据类型
- 基本数据类型就是赋的值是真实的值
- 引用数据类型赋的值是地址值,引用其他空间中的数据
- 可以理解为基本数据类型的赋值操作都是在栈内存中实现的,而引用数据类型的赋值操作需要用到堆内存
this的内存原理
- this的作用:区分局部变量和成员变量
- this的本质:所在方法调用者的地址值