前言
本博客文章已收录至专栏Java SE,阅读其他有关博客笔记请转至该专栏下查阅
传送门 -->程序员雨空集_Java SE专栏
面向对象思想
- 一种符合人类思维习惯的编程思想
想象一下,你是一个汽车制造工厂的设计师,要设计一辆汽车。在面向对象的思想中,你会将汽车看作是一个对象,这个对象有自己的属性和方法
首先,你会定义一个汽车类(Car class),这个类是一个模板,描述了汽车的共同特征和行为。在这个类中,你会定义汽车的属性,比如颜色、品牌、型号等。然后,你会定义一些方法,比如启动、加速、刹车等。这些方法描述了汽车可以做的事情
接下来,你可以创建多个汽车的实例(对象),比如一辆红色的宝马、一辆蓝色的奔驰等。每个汽车对象都有自己独立的属性值,比如颜色、品牌、型号等。你可以通过调用汽车对象的方法来执行相应的操作,比如启动汽车、加速、刹车等
- 再简单一点:
面向:拿、找
对象:能做事情的东西
面向对象编程:拿东西过来做对应的事情
- 面向对象核心概念:
即面向对象的三大特点
- 封装性
封装是将数据和操作数据的方法封装在一个对象中,通过定义类来实现。对象的内部数据对外部是不可见的,只能通过对象提供的方法来访问和操作数据。封装可以隐藏实现的细节,提高代码的可维护性和可重用性
- 继承性
继承是通过定义一个新的类来继承已有类的属性和方法。子类可以继承父类的属性和方法,并可以在此基础上进行扩展和修改。继承可以实现代码的重用,减少代码的冗余
- 多态性
多态是指同一类型的对象在不同的情境下可以表现出不同的行为。多态通过方法的重写和重载实现。在运行时,根据对象的实际类型来调用相应的方法,实现动态绑定。多态可以增加代码的灵活性和可扩展性
先了解即可,慢慢学到
类与对象
想象一下,你是一个汽车制造工厂的设计师,要设计一辆汽车。在面向对象的思想中,你会将汽车看作是一个对象,这个对象有自己的属性和方法
首先,你会定义一个汽车类(Car class),这个类是一个模板,描述了汽车的共同特征和行为。在这个类中,你会定义汽车的属性,比如颜色、品牌、型号等。然后,你会定义一些方法,比如启动、加速、刹车等。这些方法描述了汽车可以做的事情
接下来,你可以创建多个汽车的实例(对象),比如一辆红色的宝马、一辆蓝色的奔驰等。每个汽车对象都有自己独立的属性值,比如颜色、品牌、型号等。你可以通过调用汽车对象的方法来执行相应的操作,比如启动汽车、加速、刹车等
照样是上面这个例子:
类:是表示某类群体的一些基本特征的抽象,对对象共同特征的描述
对象:一个具体的能帮我们起到作用的东西,是真实存在的具体实例
再简单些:
学生可以看成一个类,而小明、张三都是学生,所以都是学生类型的对象
类的定义
1. 类的组成
类主要由属性和行为两部分组成。
- 属性:这部分描述类的数据特性,也称为成员变量或属性。例如,如果有一个
Person
类,那么它可能有name
、age
等属性。 - 行为:这部分描述类可以执行的操作,也称为方法。方法定义了类的行为和功能。继续上面的例子,
Person
类可能有eat()
、walk()
等方法。
2. 类的定义步骤
- ①定义类:在Java中使用
class
关键字来定义类。
class Person {
// ...
}
- ②编写类的成员变量:在类内部定义成员变量。
class Person {
//成员变量
String name;
int age;
}
- ③编写类的成员方法:在类内部定义方法。这些方法可以操作类的属性。
class Person {
//成员变量
String name;
int age;
//成员方法
public void eat() {
System.out.println(name + " is eating...");
}
public void walk() {
System.out.println(name + " is walking...");
}
}
对象的创建与使用
1. 创建对象的格式:
- 类名 对象名 = new 类名();
这是创建对象的基本格式。首先使用类名来声明一个对象引用,然后使用new
关键字配合类名来实例化对象。
例子:
Person person = new Person();
在这里,Person
是类名,person
是对象名。我们通过new Person()
创建了一个Person
类型的新对象,并将其引用赋给了person
。
2. 调用成员的格式:
- 对象名.成员变量
这是用来访问对象的成员变量的方法。通过.
操作符,我们可以访问对象的属性。
例子:
person.name = "Alice";
int age = person.age;
- 对象名.成员方法();
这是用来调用对象的成员方法的方法。与访问属性类似,我们也使用.
操作符来调用对象的方法。
例子:
person.eat();
person.walk();
定义类的注意事项
- 类名首字母建议大写,需要见名知意,驼峰命名
- 一个Java文件中可以定义多个class类,且只能一个类是public修饰,而且public修饰的类名必须成为代码文件名
具体可以参考这个
--> 📎Alibaba阿里巴巴Java开发手册终极版.pdf <--
小驼峰命名法适用于变量名和方法名。如果只有一个单词,那么该单词全部小写,例如:name。如果是多个单词,从第二个单词开始,每个单词的首字母大写,例如:firstName、maxAge
大驼峰命名法适用于类名。如果只有一个单词,那么该单词的首字母大写,例如:Demo、Test。如果是多个单词,每个单词的首字母都需要大写,例如:HelloWorld
- 成员变量的完整定义格式是: 修饰符 数据类型 变量名称 = 初始化值;
一般无需指定初始化值,存在默认值
初始默认值如下:
数据类型 | 明细 | 默认值 |
基本类型 | byte、short、int、long | 0 |
float、double | 0.0 | |
boolean | false | |
引用类型 | 类、接口、数组、String | null |
类与对象小练习
学生对象-练习
- 需求:首先定义一个学生类,然后定义一个学生测试类,在学生测试类中通过对象完成成员变量和成员方法的使用
- 分析:
-
- 成员变量:姓名,年龄…
- 成员方法:学习,做作业…
示例:
// 学生类
public class Student {
// 成员变量
String name; // 姓名
int age; // 年龄
// 成员方法:学习
public void study() {
System.out.println(name + "正在学习...");
}
// 成员方法:做作业
public void doHomework() {
System.out.println(name + "正在做作业...");
}
}
// 学生测试类
public class StudentTest {
public static void main(String[] args) {
// 创建学生对象
Student student = new Student();
student.name = "张三";
student.age = 20;
// 测试学习方法
student.study();
// 测试做作业方法
student.doHomework();
}
}
//输出:
张三正在学习...
张三正在做作业...
封装
为什么需要封装
在Java中,封装可以被认为是一个保护屏障,防止本类的代码和数据被外部程序随机访问
封装的主要目的是确保对象的状态(即它的数据元素)不能被外部程序直接访问,而是通过该类提供的方法进行访问和操作。这意味着,类的内部表示和实现是隐藏的,只暴露给外部程序一个简洁、明了的接口。这样的机制可以确保数据的安全性和完整性,因为用户只能通过类提供的方法对数据进行操作,而不能直接修改数据的内部状态。
为了实现封装,我们通常会将类的成员变量设置为私有(private),这样它们就不能被外部程序直接访问。然后,我们提供公共的(public)getter和setter方法,用于读取和修改这些私有成员变量的值。这样,我们就可以控制对内部数据的访问,确保数据的安全性和一致性。
*Java中的访问控制
当我们编写Java程序时,会涉及到访问类、变量、方法和构造函数的权限问题。访问权限修饰符就是用来控制这些成员的可见性和访问级别的
public(公共):使用public修饰的成员可以被任何其他类访问。也就是说,其他类可以直接访问被public修饰的类、变量、方法和构造函数。这是最高级别的访问权限修饰符
protected(受保护):使用protected修饰的成员在同一包中的其他类可以访问,而且继承该类的子类也可以访问。但是对于不同包中的类,只有在其子类中才可以访问protected成员。protected成员不能被其他包中的类直接访问
default(默认):如果没有使用任何访问权限修饰符,默认访问级别为default(也称为包级别)。默认访问级别只允许在同一包中的类访问。也就是说,只有在同一个包中的类才能直接访问默认修饰的成员。
private(私有):使用private修饰的成员只能在同一类中访问,其他类无法直接访问。private成员对于类外部是不可见的,只能通过类的公共方法间接访问
封装思想
概述:
- 是面向对象三大特征之一(封装,继承,多态)
- 对象代表什么,就得封装对应的数据,并提供数据对应的行为
- 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问成员变量private,提供对应的getXxx()/setXxx()方法
在Java面向对象编程中,封装(Encapsulation)是一种核心思想。封装的具体含义是把对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类提供的方法进行操作。
封装的主要目的有以下几点:
- 隐藏内部实现细节:将对象的内部实现细节隐藏起来,只暴露必要的接口。这使得外部程序无法直接访问对象的内部数据,只能通过对象提供的方法进行访问和操作。
- 提高代码的可维护性:由于外部程序不能直接访问对象的内部数据,只能通过对象提供的方法进行访问,因此在对象内部实现发生改变时,只要方法的接口保持不变,外部程序就不需要修改。这降低了代码维护的成本。
- 控制对内部数据的访问:通过封装,我们可以在对象中设置一些私有属性,只允许通过特定的方法进行访问和修改。这样可以有效地防止外部程序对数据进行不合法的操作,提高了数据的安全性。
在Java中,封装的实现通常通过使用访问修饰符(如private、protected)来控制类成员的可见性。一般来说,类的字段通常设置为私有(private),而通过公有的(public)getter和setter方法来获取和修改这些字段的值。这就是封装的基本实现方式。
如何实现封装
在定义一个类时,将类中的属性私有化,用private关键字修饰类的属性,被私有化的属性只能在类中被访问
如果外界想要访问私有属性,则必须通过setter和getter方法设置和获取属性值
private是一个权限修饰符,可以用来修饰成员(成员变量,成员方法)
- 被private修饰的成员,只能在本类进行访问,针对private修饰的成员变量,
- 如果需要被其他类使用,提供相应get/set的操作
-
- 提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰
- 提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰
class Student {
//成员变量
private String name;
private int age;
//get/set方法
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
public void show() {
System.out.println(name + "," + age);
}
}
// 学生测试类
public class StudentDemo {
public static void main(String[] args) {
//创建对象
Student s = new Student();
//使用set方法给成员变量赋值
s.setName("林青霞");
s.setAge(30);
s.show();
//使用get方法获取成员变量的值
System.out.println(s.getName() + "---" + s.getAge());
System.out.println(s.getName() + "," + s.getAge());
}
}
// 输出:
林青霞,30
林青霞---30
林青霞,30
this关键字
成员变量与局部变量
成员变量: 成员变量是定义在类中的变量。它们属于类的一部分,每个对象都有自己的一份成员变量副本。成员变量在对象创建时被分配内存,在对象销毁时释放内存。例如,在一个人的类中,名字和年龄可以作为成员变量。成员变量可以被类中的所有方法访问和修改
局部变量: 局部变量是定义在方法、代码块或构造方法中的变量。它们只在定义它们的方法中可见。局部变量在方法执行时创建,在方法执行结束后销毁。例如,在一个计算器类中,add方法中的两个参数a和b可以作为局部变量。局部变量只能在定义它们的方法中访问,其他方法无法直接访问
代码块:简单解释就是代码块是由大括号{ }包围的一段代码。构造方法后面马上会讲到
public class Example {
// 成员变量
private int memberVariable;
// 构造方法
public Example(int memberVariable) {
this.memberVariable = memberVariable;
}
// 成员方法
public void displayInfo(int localVariable) {
// 局部变量
System.out.println("成员变量: " + memberVariable);
System.out.println("局部变量: " + localVariable);
}
public static void main(String[] args) {
Example example = new Example(10);
int localVariable = 20;
example.displayInfo(localVariable);
}
}
输出结果将会是:
成员变量: 10
局部变量: 20
就近原则
谁离我近,我就用谁
也就是说,当存在多个同名变量时,系统会优先访问当前作用域内的变量
public class Student{
privite string name;
private int age;
public void output(){
int age = 10;
System.out.println(age);
}
}
像上面的情况,如果我需要输出的age的值,输出方法里局部变量的值,还是student类里成员变量的值
根据就近原则,系统会输出方法里局部变量的age值
如果需要使用类里成员变量的值,就需要使用this关键字
public class Student{
privite string name;
private int age;
public void output(){
int age = 10;
System.out.println(this);
}
}
这样子,就会使用到类里成员变量的值
例子:
public class Student {
private String name;
private int age;
// 构造方法,初始化Student对象的name和age
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void output() {
// 局部变量age
int age = 20;
System.out.println("局部变量age: " + age);
// 使用this关键字访问成员变量
System.out.println("成员变量age: " + this.age);
}
public static void main(String[] args) {
// 创建一个Student对象,并初始化name和age
Student student = new Student("张三", 25);
student.output();
}
}
// 输出:
局部变量age: 20
成员变量age: 25
this关键字
在Java开发中,当成员变量和局部变量重名时,需要使用到this关键字来辨别
作用:
- 用this关键字调用本类中的成员变量
- 用this关键字调用本类中的成员方法
- 用this关键字调用本类中的构造方法
假设有一个Person类,其中有一个成员变量name和一个成员方法getName(),以及一个构造方法Person(String name)
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
- 使用this关键字调用本类中的属性:
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void printName() {
System.out.println(this.name);
}
}
在printName()方法中,使用this.name来访问本类中的name属性。
- 使用this关键字调用成员方法:
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void printName() {
System.out.println(this.getName());
}
}
在printName()方法中,使用this.getName()来调用本类中的getName()方法
- 使用this关键字调用本类中的构造方法:
public class Person {
private String name;
private int age;
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this(name); // 调用本类中的构造方法Person(String name)
this.age = age;
}
}
在第二个构造方法中,使用this(name)来调用本类中的构造方法Person(String name)。这样可以避免重复的代码
构造方法
构造方法定义
构造方法(也叫做构造器、构造函数)是类的一个特殊成员方法
作用:在类实例化对象时自动调用,以完成对象数据的初始化
书写格式:
- 方法名与类名一致,大小写也要一样
- 没有返回值类型,void 都没有
- 没有具体的返回值(不能由return带回结果)
无参构造方法
创建一个Student类的无参构造方法
class Student{
public Student(){
System.out.println("我是一个无参构造方法");
}
}
创建一个StudentTest测试类
public class StudentTest {
public static void main(String[] args) {
Student stu = new Student();
}
}
在测试类运行时,用Student类创建对象stu后会自动调用,完成初始化
有参构造方法
创建一个Student类的有参构造方法
class Student{
private String name;
private int age;
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;
}
}
创建一个StudentTest测试类
public class StudentTest {
public static void main(String[] args) {
Student stu = new Student("张三",18);
System.out.println(stu.getName());
System.out.println(stu.getAge());
}
}
构造方法注意点:
- 如果没有定义构造方法,系统将给出一个默认的无参数构造方法
- 如果定义了构造方法,系统将不再提供默认的构造方法
构造方法的重载
构造方法的重载是指在同一个类中定义多个具有不同参数列表的构造方法
通过构造方法的重载,我们可以根据不同的参数列表来创建不同的对象,并完成对象的初始化
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;
}
}
建议:
无论是否使用,都手动书写无参数构造方法,和带全部参数的构造方法