Java面向对象
前言
面向对象是相对于面向过程来说的。面向过程思想即分析解决问题的具体步骤,然后根据步骤设计解决问题的具体思路和方法,一步一步地解决问题;面向对象思想则是将现实世界抽象成一个个对象,研究每个对象的属性和行为,描述对象在整个解决问题的过程中的行为。
对于复杂事物的描述,为了从宏观上把握系统的整体架构,我们通常使用面向对象的思想来分析整个系统,但是,细化到解决问题的具体步骤,我们仍然需要使用面向过程的思想去处理具体问题。
1.什么是面向对象
面向对象编程:OOP-----Object Oriented Programming
面向对象编程的本质就是:以类的方式组织代码,以对象的形式封装数据。
核心思想:抽象
三大特性:封装、继承、多态
2.方法
2.1方法的定义
修饰符 返回值类型 方法名(形参列表){
方法体;
return 返回值;
}
返回的数据要和定义的返回值类型一致,当方法不需要返回值是,用void关键字定义方法;
形参列表可以为空,也可以定义多个参数,多个参数之间用逗号隔开;
return关键字有结束方法的作用,当方法执行过return语句后,就代表方法执行结束。
方法名命名规范:
- 由字母、数字、$(美元符)、_(下划线)组成
- 不能以数字开头
- 不能定义为Java中的关键字和保留字
- 首字母小写,驼峰式命名(多个单词组成时,后面每个单词首字母大写)
- 见名知意
- 例:myMethod()
2.2方法的调用
-
静态方法
——用static关键字修饰的方法
可以直接通过类名.方法名()调用
package com.th.oop;
public class Teacher {
// 静态方法
public static void teach(){
System.out.println("老师正在上课");
}
}
package com.th.oop;
public class Test {
public static void main(String[] args) {
// 直接通过类名调用静态方法
Teacher.teach();
}
}
-
非静态方法
——没有使用static关键字修饰的方法
实例化方法所在类的对象,通过对象名.方法名()调用
package com.th.oop;
public class Student {
// 非静态方法
public void study(){
System.out.println("学生正在学习");
}
}
package com.th.oop;
public class Test {
public static void main(String[] args) {
// 实例化一个学生类的对象
Student student = new Student();
// 通过student对象调用Student类中的study()方法
student.study();
}
}
3.类与对象
3.1类与对象的关系
在Java中,类是一种抽象的引用数据类型,它并不能代表某一具体的事物,而代表了一类事物,它是对一类事物整体的描述和定义。
对象是类的具体实例,能够表现出具体的属性和行为,而非一个抽象的概念。
3.2对象的创建与初始化
3.2.1类的创建
类由属性和方法组成
package com.th.oop;
public class Student {
// 属性,也叫字段
String name;
int age;
// 方法
public void study(){
// this代表当前类
System.out.println(this.name + "正在学习");
}
}
3.2.2对象的创建
使用new关键字创建对象的时候,会给创建的对象分配内存空间,此外,还会给创建好的对象进行默认的初始化以及调用类中的构造器。
package com.th.oop;
public class Test {
public static void main(String[] args) {
/*
* 通过new关键字实例化一个Student类的对象
* 类实例化之后会返回一个自己类型的对象
* xiaoming对象就是Student类的一个具体实例
* xiaohong对象也是Student类的一个具体实例,这里只是用作测试,方便理解,实际中不建议使用拼音给变量命名
*/
Student xiaoming = new Student();
Student xiaohong = new Student();
}
}
3.2.3构造方法
类中的构造方法也叫构造器,在类进行实例化对象的时候一定会调用类的构造方法。
构造方法的特点:
- 构造方法的名字必须和类名相同
- 构造方法没有返回值,也不能写void
构造方法的作用:
- 使用new关键字创建对象的过程,其本质就是调用类的构造方法
- 初始化对象的值
注意点:
- 类本身默认存在一个无参构造方法,当在类中定义了有参构造方法之后,本来类中默认存在的无参构造方法就不存在了,此时就无法使用无参构造方法实例化对象,若想要使用无参构造方法,就需要在类中显式定义一个无参构造方法。
package com.th.oop;
public class Person {
String name;
int age;
// 显式定义无参构造方法
public Person() {
}
// 定义类的有参构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
package com.th.oop;
public class Test {
public static void main(String[] args) {
// 调用无参构造方法创建对象
Person person = new Person();
// 手动为对象的属性赋值
person.name = "小明";
person.age = 5;
// 调用有参构造方法创建对象
new Person("张三", 18);
}
}
3.2.4方法的重载
在同一个类中,方法名相同,参数列表不同的多个方法构成重载。
package com.th.oop;
public class OverLoadTest {
// 定义第一个方法,这里为了方便测试,将方法定义为静态方法,实际上,方法是否构成重载与static没有关系
public static int add(int a, int b) {
return a + b;
}
// 定义与第一个方法名称相同,参数类型不同的方法
public static double add(double a, double b) {
return a + b;
}
// 定义与第一个方法名称相同,参数个数不同的方法
public static int add(int a, int b, int c) {
return a + b + c;
}
public static void main(String[] args) {
System.out.println("调用add(int, int)方法" + add(1, 2));
System.out.println("调用add(double, double)方法" + add(1.0, 2.0));
System.out.println("调用add(int, int, int)方法" + add(1, 2, 3));
}
}
4.三大特性
4.1封装
封装即属性私有化,使用private关键字修饰类的属性,使外部成员无法直接访问这些私有属性,对外只提供少量的方法供外部成员使用。
程序设计追求高内聚,低耦合,高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合即仅暴露少量方法供外部成员使用。
package com.th.oop;
public class Student {
// 使用private关键字使属性私有化
private String name; // 姓名
private int age; // 年龄
private char gender; // 性别
/*
* 定义get、set方法供外部成员使用
* 可以自动生成,快捷键:Alt + Insert
*/
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;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
}
封装的意义:
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 提高代码的可维护性
- 统一外部接口
4.2继承
继承是类和类之间的一种关系,产生继承关系的两个类,一个为子类,一个为父类。子类使用extends关键字继承父类,extends有扩展之意,子类是父类的扩展,子类不仅继承了父类的非私有成员,子类还可以定义自己的属性和方法,拥有更丰富的功能。
Java中只存在单继承,一个子类只能继承一个父类,一个父类可以被多个子类继承。
父类:
package com.th.oop;
public class Person {
// 父类定义属性
String name;
int age;
// 父类定义方法
public void say(){
System.out.println("说话");
}
}
子类:
package com.th.oop;
public class Student extends Person{
// 子类可以定义自己的属性
double high;
double weight;
// 子类可以定义自己的方法
public void study(){
System.out.println("学生在学习");
}
}
测试:
package com.th.oop;
public class Test {
public static void main(String[] args) {
// 实例化子类Student对象
Student student = new Student();
// 子类对象可以调用父类的非私有属性和方法
student.name = "小明";
student.say();
// 子类对象可以调用自己的属性和方法
student.high = 168;
student.study();
}
}
this关键字和super关键字
- this指代当前类对象的引用
- 调用当前类的属性
- 调用当前类的成员方法
- 调用当前类的构造方法,只能放在第一行
- super指代当前类的父类对象的引用
- 调用父类的属性
- 调用父类的成员方法
- 调用父类的构造方法,只能放在第一行
4.3多态
方法的重写
在继承的基础上,子类重新编写父类中方法的方法体,叫做方法的重写。
产生多态的条件:
- 子类继承父类
- 子类重写父类的方法
- 父类的引用指向子类的对象
父类(Person):
package com.th.oop;
public class Person {
// 父类定义属性
String name;
int age;
// 父类定义方法
public void say(){
System.out.println("说话");
}
}
子类(Student):
package com.th.oop;
public class Student extends Person {
// 子类Student重写父类Person的say()方法
@Override
public void say() {
System.out.println("学生说话");
}
}
子类(Teacher):
package com.th.oop;
public class Teacher extends Person {
// 子类Teacher重写父类Person的say()方法
@Override
public void say() {
System.out.println("老师说话");
}
}
测试:
package com.th.oop;
public class Test {
public static void main(String[] args) {
// 实例化子类Student对象和Teacher对象
// 父类的引用指向子类的对象
Person student = new Student();
Person teacher = new Teacher();
// 同是父类Person类型的对象,调用重写后的方法,产生不同的结果,这就是多态
student.say();
teacher.say();
}
}
/*
* 运行结果:
* 学生说话
* 老师说话
*/
5.抽象类与接口
5.1抽象方法
使用abstract关键字定义的方法称为抽象方法,抽象方法没有方法体,必须定义在抽象类中。抽象方法本身没有任何意义,除非它被重写,在子类中实现其具体的功能。
package com.th.oop;
public abstract class Person {
// 定义抽象方法
public abstract void run();
}
5.2抽象类
- 使用abstract关键字修饰类成为抽象类。
- 抽象类除了可以定义抽象方法之外,其他方面与普通类并无区别。
- 抽象类中可以定义属性和成员方法,也可以定义构造方法。
- 抽象类中所有的抽象方法必须由其非抽象子类实现。
- 抽象类可以作为数据类型。
- 抽象类不能被实例化。
抽象类Person:
package com.th.oop;
public abstract class Person {
// 定义属性
String name;
int age;
// 定义常量
public static final int LEG_NUMBER = 2;
// 定义抽象方法
public abstract void run();
// 定义成员方法
public void say() {
System.out.println("说话");
}
// 定义无参构造方法
public Person() {
}
// 定义有参构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
非抽象子类Student:
package com.th.oop;
public class Student extends Person {
// 重写父类Person的抽象方法
@Override
public void run() {
System.out.println("学生跑步");
}
}
5.3接口
- 接口可以看作是纯粹的抽象类。
- 接口使用interface关键字进行定义。
- 接口中只能定义抽象方法和常量。
- 接口中定义的抽象方法默认使用public abstract关键字修饰,可以省略。
- 接口中定义的常量默认使用public static final关键字修饰,可以省略。
- 接口中的抽象方法由其实现类重写来实现其功能。
- 接口是多继承,多实现的。一个接口可以继承多个接口,也可以被多个类实现,一个类也可以实现多个接口。
接口:
package com.th.oop;
public interface Behavior {
// 定义常量,默认使用public static final关键字修饰,可以省略
public static final int LEG_NUMBER = 2;
// 定义抽象方法,默认使用public abstract关键字修饰,可以省略
public abstract void run();
}
实现类Student:
package com.th.oop;
public class Student implements Behavior {
// 重写接口Behavior中的抽象方法
@Override
public void say() {
System.out.println("学生说话");
}
@Override
public void run() {
System.out.println("学生跑步");
}
}
实现类Teacher
package com.th.oop;
public class Teacher implements Behavior{
// 重写接口Behavior中的抽象方法
@Override
public void say() {
System.out.println("老师说话");
}
@Override
public void run() {
System.out.println("老师跑步");
}
}
测试:
接口的引用可以指向实现类的对象,调用重写后的方法,产生不同的结果,实现多态。
package com.th.oop;
public class Test {
public static void main(String[] args) {
// 实例化实现类Student对象和Teacher对象
// 接口的引用可以指向实现类的对象
Behavior student = new Student();
Behavior teacher = new Teacher();
student.say();
teacher.say();
}
}
/*
* 运行结果:
* 学生说话
* 老师说话
*/