本节学习目标:
面向对象是软件开发方法,一种编程范式。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
面向对象 - 百度百科
早期的计算机编程是基于面向过程的方法,例如实现算术运算1+1+2 = 4,通过设计一个算法就可以解决当时的问题。随着计算机技术的不断提高,计算机被用于解决越来越复杂的问题。一切事物皆对象,通过面向对象的方式,将现实世界的事物抽象成对象,现实世界中的关系抽象成类、继承,帮助人们实现对现实世界的抽象与数字建模。通过面向对象的方法,更利于用人理解的方式对复杂系统进行分析、设计与编程。同时,面向对象能有效提高编程的效率,通过封装技术,消息机制可以像搭积木一样快速开发出一个全新的系统。面向对象是指一种程序设计范型,同时也是一种程序开发的方法。对象是类的具体化实现。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。
面向对象 - 百度百科
面向对象(Object Oriented)是一种编程思想,是人类最自然的实装思考方式,它将所有预处理的问题抽象为对象,同时了解这些对象具有哪些相应的属性以及展示这些对象的行为,
以解决这些对象面临的一些实际问题,这样就在程序开发中引入了面向对象设计的概念,面向对象设计实质上就是对现实世界的对象进行建模操作。
对象(Object)是类的实例(Instance),是事物存在的实体。对象拥有属性(特征)和行为(动作),比如一条狗是一个对象,它的颜色为黄色、品种为柴犬等,它的行为有吃、吠叫、摇尾巴等。
类(Class)为对象的模板,是同一类事物的统称,如人类,鸟类等。类描述对象的属性(特征)和行为(动作)。比如汽车类,汽车的属性有类型,品牌等,汽车的行为有行驶,转弯,刹车等。几乎所有的汽车都拥有上述的特征和行为。
在Java语言中,对象的行为对应类中的成员方法,对象的属性对应类中的成员变量(也称为实例变量)。
类(面向对象)的三大特性:
封装(Encapsulation):
封装是面向对象的核心思想,将对象的属性和行为都封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。
比如用户使用计算机时,只需要使用鼠标和键盘就可以实现一些功能,无需知道计算机内部是怎么实现的。
继承(Inheritance):
类与类之间同样具有关联,继承是关联的一种。继承其他类的类被称为子类,被继承的类被称为父类(或超类)。子类继承父类,子类的对象也拥有父类的一些属性和行为。
比如等边三角形是三角形的一种,等边三角形类继承于三角形类,等边三角形拥有三角形的一些特性。
多态(Polymorphism):
多态是同一个行为让不同的对象执行得到不同的结果,是对象多种表现形式的体现。
比如打印机都可以进行打印操作,而黑白打印机只能打印出黑白色,彩色打印机可以打印出多种颜色。
类(Class)是封装对象的属性和行为的载体,在Java语言中的对象的属性以成员变量(实例变量)的形式存在,对象的行为以成员方法的形式存在。
Java中对象的属性对应类中的成员变量(Field),比如图书(Book),它拥有名称(name),类别(category),作者(author)等属性:
public class Book { private int id; // 图书ID private String name; // 图书的名称 private String category; // 图书的分类 private String author; // 图书的作者 }
分析上述代码,Java中使用class
关键字来定义类。Book为类的名称,同时在Book类中定义了三个成员变量。成员变量的类型可以为基本数据类型,也可以为引用数据类型。
成员变量可以设置初始值(如private String name = "老人与海";
),也可以不设置初始值。如果不设置初始值时,类实例化后会有默认值。
Java中对象的行为对应类中的成员方法(Method),比如计算器的开机(open)、关机(close)与加法计算(sum)等行为:
public class Calculator { public void open() { System.out.println("计算器打开了"); } public void close() { System.out.println("计算器关闭了"); } public int sum(int x, int y) { return x + y; } }
一个成员方法可以有参数,参数类型可以是基本数据类型也可以是引用数据类型。成员方法可以有返回值,返回值类型可以是基本数据类型也可以是引用数据类型,也可以是void
关键字(无返回值)。
方法体中可以使用return
关键字,用于方法返回值,同时执行return
语句之后方法的执行将被终止。
Java中的权限修饰符主要为public
,private
,protected
和缺省(默认,不指定),这些修饰符控制着外部对类的成员变量和成员方法的访问。
private
:被private
关键字修饰的方法和成员变量是私有的,只能在本类中使用;public
:被public
关键字修饰的方法和成员变量是公有的,任何类都能使用;protected
:被protected
关键字修饰的方法和成员变量是受保护的,只能在同一个包(后续章节将展示具体细节)下的类使用,但可以在不同包下的子类使用。修饰符访问权限表一览:
修饰符 | 本类 | 不同包下其他类 | 同一包下其他类 | 不同包下的子类 | 同一包下的子类 |
---|---|---|---|---|---|
private | 可见 | 不可见 | 不可见 | 不可见 | 不可见 |
public | 可见 | 可见 | 可见 | 可见 | 可见 |
protected | 可见 | 不可见 | 可见 | 可见 | 可见 |
缺省 | 可见 | 不可见 | 可见 | 不可见 | 可见 |
在成员方法内定义的变量被称作局部变量(Local Variable)。比如在例子中:
public class Car { public String getType() { String type = "敞篷车"; return "车的类型为" + type; } public String getBrand(String brand) { return "车的品牌为" + brand; } }
getType()
方法体里的type
即为局部变量。getBrand()
方法的形参brand
也看做局部变量。
{}
)的范围里。构造方法(Constructor,又称为构造器)是一种特殊类型的成员方法。它与类名同名且不需指定返回值,
对象创建时调用的方法就是构造方法,构造方法通常用来初始化成员变量:
public class Person { private String name; private int age; public Person() { this.name = "张三"; this.age = 21; } public Person(String name, int age) { this.name = name; this.age = age; } public static void main(String[] args) { Person person1 = new Person(); System.out.println(person1.name + person1.age); Person person2 = new Person("王五", 31); System.out.println(person2.name + person2.age); } }
运行结果:
张三21 王五31
构造方法分为无参构造方法和有参构造方法。顾名思义无参构造方法就是没有参数的构造方法,通常需要给成员变量指定默认值。
有参构造方法就是有参数的构造方法,可以在对象创建时指定具体的成员变量值。
在成员方法中调用本类的成员变量或成员方法,需要使用this
关键字,this
关键字代表本类对象的引用。this
也可以作为方法的返回值(需要对应返回值类型)。
如果在编写类时没有编写构造方法,那么在编译时Java会自动给我们加上一个无参构造方法,并且方法体内无任何语句。
由static
关键字修饰的变量、常量与方法被称为静态变量(类变量),静态常量与静态方法(类方法)。
public class RoundCalculator { private final static double PI = 3.1415; // 静态常量 private static String help = "输入圆的半径即可求出面积"; // 静态变量 public static void getHelp() { // 静态方法 System.out.println(help); } public static void calculate(double radius) { // 静态方法 System.out.println("半径为" + radius + ",面积为:" + (RoundCalculator.PI * radius * radius)); } }
静态变量,常量与方法被称为静态成员,属于类所有,可以在本类和其他类中以类名.静态类成员
的方式调用(静态成员同样受到访问修饰符的约束)。
静态变量和常量在使用中只会被初始化一次,同时在内存中只有一份数据。
静态方法(又称为类方法)属于类所有,方法体中不可以使用this
关键字,也不可以直接调用非静态方法(成员方法)。
如果想要调用非静态方法,则需要使用new
关键字创建非静态方法所在的类的对象后,使用对象.成员方法
形式调用。
主方法(main()
方法)是类的入口点,它定义了程序从何处开始;主方法提供了对程序流向的控制,Java编译器通过主方法来执行程序:
public static void main(String[]args) { // 方法体 }
args[0]
~args[n]
分别代表执行程序的第一个参数到第n个参数,可以使用args.length
获取参数的个数。Java是一门面向对象的程序设计语言,对象(Object)是类的一个实例(Instance)。在Java中所有的问题都通过对象来处理,对象可以操作类的属性和方法解决响应的问题。
在Java语言中通过new
关键字调用类的构造方法来创建对象(也称为类的实例化):
public class Teacher { public Teacher() { System.out.println("调用了Teacher的构造方法"); } public static void main(String[] args) { Teacher teacher = new Teacher(); } }
运行结果:
调用了Teacher的构造方法
teacher变量被创建出来时,就是一个Teacher
对象的引用,这个引用在内存中为对象分配了存储空间。
每个对象都是相互独立的,在内存中占据独立的内存地址。
使用new
关键字创建一个对象后,可以使用对象.类成员
来获取对象的属性和行为:
public class Student { private String name; private String hobby; public Student(String name, String hobby) { this.name = name; this.hobby = hobby; } public void doingSth() { System.out.println(this.name + "正在" + this.hobby); } public static void main(String[] args) { Student student1 = new Student("小明", "学习英语"); student1.doingSth(); Student student2 = new Student("小红", "踢毽子"); student2.doingSth(); } }
运行结果:
小明正在学习英语 小红正在踢毽子
可以看到两个对象虽然调用了同一个成员方法,结果却不相同,因为它们是独立的两个对象,这两个对象占据的内存地址也是独立的。
如果希望两个对象之间共享数据,即一个对象对数据做出更改,另一个对象访问此数据时得到的是更改过的值,那么可以使用静态变量:
public class Book { private final static String title = "鲁滨逊漂流记"; // 静态常量 private static int amount = 30; // 静态变量 public void sale(int amount) { System.out.println(title + "售出了" + amount + "本"); Book.amount -= amount; } public void getAmount() { System.out.println(title + "还剩余" + Book.amount + "本"); } public static void main(String[] args) { Book book1 = new Book(); book1.getAmount(); book1.sale(5); Book book2 = new Book(); book2.getAmount(); } }
运行结果:
鲁滨逊漂流记还剩余30本 鲁滨逊漂流记售出了5本 鲁滨逊漂流记还剩余25本
在Java语言中尽管一切都可以看做对象,但真正的标识符只是一个引用。如一个Book类的引用为:
Book book;
通常一个引用不一定需要有一个对象相关联。
引用只是存放着一个对象的内存地址的变量,并非存放着一个对象,严格地说,引用和对象是不同的,不过可以将这种区别忽略。
可以简单的说book
是Book
类的一个对象,实际上book
只是一个Book
对象的引用。
Java中有两种方式比较对象,一个是使用==
运算符,另一个使用equals()
方法。实质上这两种比较方式有本质区别:
public class Compare { public static void main(String[] args) { String str1 = new String("abc"); String str2 = new String("abc"); String str3 = str2; System.out.println("str1==str2的运算结果:" + (str1 == str2)); System.out.println("str1.equals(str2)的运算结果:" + (str1.equals(str2))); System.out.println("str2==str3的运算结果:" + (str2 == str3)); } }
运行结果:
str1==str2的运算结果:false str1.equals(str2)的运算结果:true str2==str3的运算结果:true
例子中的equals()
方法为String
字符串类继承于Object
类的方法,用于比较两个字符串变量引用所指的字符串对象的内容是否相同,
而==
运算符比较的是两个字符串变量引用所指的字符串对象的内存地址是否相同(即所指的是否为同一个字符串对象)。
每个对象都有生命周期,当对象的生命周期结束时,分配给该对象的内存区域将会被回收。在其他语言中(如C++)需要手动回收废弃的对象,
但是Java拥有一套完整的垃圾回收机制(具体细节将会在后续章节展示)。不必担心废弃的对象占用内存,垃圾回收器将自动回收无用的但占用内存的资源。
主要在以下两种情况时,对象会被Java虚拟机视为垃圾:
null
,则这个对象会被视为垃圾。