面向对象和面向过程
我们知道Java是面向对象的编程语言,而C语言是面向过程的编程语言,那什么是面向对象,什么是面向过程呢?
- C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题;面向过程注重的是过程,在整个过程中所涉及的行为,就是功能。
- Java是面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成;面向对象注重的是对象,也就是参与过程所涉及到的主体,是通过逻辑将一个个功能实现连接起来。
我们来看两个例子更好的理解面向过程和面向对象。
- 蛋炒饭和盖浇饭的例子,我们可以将制作蛋炒饭的过程理解成面向过程的,在制作蛋炒饭的过程中,我们需要关注的是每一步该放什么,先炒鸡蛋,在放饭,调料等,出锅的时候加上葱花;而盖浇饭的制作就可以理解成是面向对象的,每一道菜都是一个对象,米饭也是一个对象,想吃什么就往米饭上加什么就可以了。
- 再来一个高大上的例子来理解面向过程和面向对象。编年体史书和纪传体史书。我们可以将编年体通史理解成是面向过程的,它以年为顺序,记录每一年发生的大事,比如说《春秋》;而纪传体史书就可以理解成是面向对象的,纪传体史书针对具体的人物书写史书,比如说《史记》。
面向对象的特性:
- 最重要的三大特性:封装、继承、多态。
- 其他特性:抽象、组合、反射等。
什么是类和对象?
对于类和对象的理解,我们可以借助C语言中的结构体。
- 我们知道C语言中的结构体是自定制类型,而类可以理解成高配的结构体,因为结构体中只包含属性,而类中不仅包含属性还包含方法。
- 现在我们知道类是一种自定制类型,那对象就比较好理解了,对象就是根据类这个自定制类型创建的变量。对象的创建过程,我们称之为类的实例化。
- 类的实例化过程,我们可以通过一个例子来加深理解,我们可以将类看做一幅建筑图纸,而对象就是根据这个图纸盖出的房子。
下面看一个类和对象实例化的代码示例:
public class Test {
public static void main(String[] args) {
Student student = new Student("sss", 24, "male");
System.out.println(student.toString());
}
}
class Student {
private String name;
private int age;
private String gender;
// 构造方法
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public String toString() {
return "Student{" + this.name
+ ", " + this.age
+ ", " + this.gender
+ "};";
}
}
运行结果如下:
我们对上述代码简单分析一下:
- Student类中,name、age、gender称为类的属性,也叫字段、成员变量;toString、Student称为类的方法,也叫成员函数。
new Student("sss", 24, "male");
就是对类进行实例化,即创建一个对象;而Student student是创建一个对象的引用。- 注意:Student()是一个特殊的方法,称为构造方法,方法名和类名相同,构造方法在类的实例化时会被自动调用,构造方法没有返回值,用于对象的初始化。
每一个类中一定至少有一个构造方法(没有明确定义,则系统会自动生成一个无参构造(若类中定义了构造方法,则默认的无参构造将不再生成)),构造方法支持重载,规则和普通方法一样。构造方法之间可以相互调用。
- this是当前对象的引用,this的出现是因为对象的方法和属性是分开存储的,因为所有对象的方法都是一致的,只有属性不同,所以在类的实例化中,不会新开辟内存空间来存储方法,只会为属性开辟空间。因此如果一个对象调用方法时,方法为了区分是哪个对象,就引入了this关键字来表示当前调用对象的引用。
- @Override(注解)表示对父类toString方法的重写,Java中有一个特殊的类Object是所有类的祖宗,Java中其他所有的类都直接或间接继承自Object类,而toString是Object的方法。toString会在println的时候自动调用,例如:
System.out.println(student.toString());
和System.out.println(student);
的效果是一样的。
我们将对象转为字符串这样的操作称为序列化。
下面我们来看一段代码,画一下其中其中变量的内存分布:
public class Test {
public static void main(String[] args) {
Student student1 = new Student("fzy", 24, "male");
System.out.println(student1);
Student student2 = new Student("lyx", 18, "female");
System.out.println(student2);
}
}
class Student {
private String name;
private int age;
private String gender;
private final int holidays = 2;
public static String nature = "people";
public static final int tuition = 8000;
// 构造方法
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public String toString() {
return "Student{name: " + this.name
+ ", age: " + this.age
+ ", gender: " + this.gender
+ ", holidays: " + this.holidays
+ ", nature: " + nature
+ ", tuition: " + tuition
+ "};";
}
}
static关键字
C语言中,我们知道static关键字有三个作用:
- 修饰局部变量,修改局部变量生命周期为程序整个运行期间;
- 修饰全局变量,修改全局变量的链接属性,将全局变量的作用域限制在当前.c文件;
- 修饰函数,修改函数的链接属性,将函数的作用域限制在当前.c文件。
Java中static关键字的作用和C语言中截然不同,下面来具体看一下:
- 修饰属性:表示该属性为类属性(静态属性),和对象无关,不论实例化出多少个对象,类属性只有一份。可以通过
类.属性
来访问,也可以通过对象.属性
来访问。
静态属性在普通方法、构造代码块、静态方法和静态代码块中都可以访问;普通属性只能在普通方法和构造代码块中访问。 - 修饰方法:表示该方法为类方法(静态方法),与对象无关,静态方法中不能使用this(当前对象的引用)和super(当前对象父类对象的引用)。
可以直接调用静态方法而无需实例化对象,静态方法可以访问静态属性,并可以修改静态属性;静态方法不能直接使用非静态属性和调用非静态方法。 - 修饰代码块:静态代码块,用于初始化静态属性,静态代码块不管实例化出多少个对象,都只会执行一次,且是最先执行。
静态代码块执行完毕后,再执行普通代码中内容,最后执行构造方法。 - 修饰内部类:被static修饰的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。
代码块
什么是代码块?
代码块就是使用{}定义的一段代码,根据代码块定义的位置以及关键字,可以分为以下四种:
- 普通代码块:定义在方法中的代码块。
public class Test {
public static void main(String[] args) {
// 普通代码块
{
System.out.println("这是一个普通代码块!");
}
}
}
- 构造代码块(实例代码块):定义在类中的代码块,构造代码块一般用于对象的初始化。构造代码块先于构造函数执行。构造方法可以传参和重载,更加灵活。相比之下,构造代码块只能做规定的初始化。
public class Test {
public static void main(String[] args) {
// 普通代码块
{
System.out.println("这是一个普通代码块!");
}
Student student = new Student("sss", 24, "male");
System.out.println(student);
}
}
class Student {
private String name;
private int age;
private String gender;
public static String nature = "people";
// 构造代码块
{
this.name = "hello, world!";
System.out.println("这是一个构造代码块!");
}
// 构造方法
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
System.out.println("这是一个构造方法!");
}
@Override
public String toString() {
return "Student{" + this.name
+ ", " + this.age
+ ", " + this.gender
+ "};";
}
}
- 静态代码块:使用static修饰的构造代码块,用于初始化静态成员属性,先于构造代码块执行,无论生成多少个对象,静态代码块只执行一次。
public class Test {
public static void main(String[] args) {
// 普通代码块
{
System.out.println("这是一个普通代码块!");
}
Student student1 = new Student("sss", 24, "male");
System.out.println(student1);
Student student2 = new Student("hehe", 18, "female");
System.out.println(student2);
}
}
class Student {
private String name;
private int age;
private String gender;
public static String nature = "people";
// 静态代码块
static {
nature = "hello, world!";
System.out.println("这是一个静态代码块!");
}
// 构造代码块
{
this.name = "hello, world!";
System.out.println("这是一个构造代码块!");
}
// 构造方法
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
System.out.println("这是一个构造方法!");
}
@Override
public String toString() {
return "Student{" + this.name
+ ", " + this.age
+ ", " + this.gender
+ "};";
}
}
- 同步代码块。
匿名对象
- 没有引用的对象称为匿名对象。
- 匿名对象只能在创建对象时使用。
- 如果一个对象只使用一次,后面就不需要了,可以考虑使用匿名对象。
代码演示:
public class Test {
public static void main(String[] args) {
new Student("sss", 24).show();
}
}
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void show() {
System.out.println("name: " + this.name
+ ", age: " + this.age);
}
}