面向对象(Object Oriented,OO)是软件开发方法。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术 [1] 发展到一定阶段后的产物。
创建一个对象
/**
* 这是一个对象:人
*/
public class Person {
// 对象的属性
private String name;
private int age;
private char sex;
// 对象的方法(功能)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
void eat(){
System.out.println("吃东西");
}
void run(){
System.out.println("跑步");
}
}
使用一个对象
public class TestPerson {
public static void main(String[] args) {
// 创建对象
Person2 person2 = new Person2();
// 调用对象给属性赋值
person2.setName("jack");
// 用对象调用方法
person2.run();
}
}
8. public static void main(String[] args) {
9. //调用其他类的方法或属性赋值,必须通过对象
10. Student s = new Student();
11. //赋值
12. s.name = "李四";
13. s.age = 18;
14. //调用方法
15. s.study();
16. Student s1 = s;
17. s = null;
18. }
局部变量:定义在函数(方法)中的那些变量。局部变量只在定义它的方法(函数)中有效。
成员变量:定义在类的成员位置上的变量。成员变量在整个类中都有效(全局变量是成员变量的俗称);成员变量又分为 实例(对象)变量 和 类变量(static静态变量)。
注意:在类中和该类的一个函数中,同时存在一个相同类型相同名称的变量,在函数被执行时,函数中优先使用定义在函数中的变量(局部变量),符合就近原则。
局部变量和成员变量的区别:
1、从定义上来讲:
局部变量定义在函数中。
成员变量定义在类中。
2、从内存存储上来讲:
局部变量随着函数的运行会在栈内存中出现,局部变量存储在栈内存中。
成员变量会随着对象的出现在堆中存在,成员变量存储在堆内存中。
3、从初始值上来讲:
局部变量在定义时需要指定初始值(局部变量没有默认值),只有初始化之后才能使用。
成员变量可以不用初始化,有默认值。
4、从存活时间上来讲(生命周期)
局部变量是随着函数的进栈在函数所属的栈内存中存在,随着函数的出栈就消失。
成员变量是随着对象的出现在堆中出现。随着对象的消失而消失。
封装(Encapsulation)是面向对象方法的重要原则,就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。(就是把过程和数据包装起来,对数据的访问只能通过已定义的接口)
this: 代表所在类的对象引用,方法被哪个对象调用,在方法中就会有一个隐式的变量this记录着调用对象的地址。
① 在类中,如果要表示成员变量,就使用this.变量名来表示;
② 当在函数中局部变量和成员变量同名的时候,在函数中如果要访问成员变量,这时需要使用this来区分;
③ 如果在函数中没有和成员变量同名的局部变量名时,在函数中可以省略this;
④ 在函数中,如果局部变量和成员变量名字和类型都一致,那么函数会先使用局部变量;
}
// this调用其它构造函数的格式: this(参数列表); // 相当于 构造函数(参数列表)
public Person(String name){
this.name = name;
}
public Person(String name, int age) {
this("jack");
this.name = name;
this.age = age;
}
子类重写父类中继承而来的方法
注意点:
① 方法名必须与父类中继承而来的方法名称一模一样.
② 方法的参数列表也要保持一致.
③ 方法的返回值也要相同.
④ 子类重写的方法访问权限修饰符必须要 大于等于
父类中重写的方法.
⑤ 重写方法不能抛出比被重写方法申明更加宽泛的异常.
我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
public class Son extends Father {
private String knowledge;
public Son(String name, int age, char gender, int money, String knowledge) {
// 说明 : 将父类中继承而来的属性, 传递给父类进行初始化.
super(name, age, gender, money);
// 说明 : 自己的属性自己初始化.
this.knowledge = knowledge;
}
public Son() {
// 构造方法的调用在构造方法中, 必须是第一条执行语句.
super();
System.out.println("调用了 Son() 无参构造方法...");
}
@Override
public void introduce() {
// 调用父类中的 introduce() 方法
super.introduce();
System.out.println("我的知识是 : " + knowledge);
}
}
public static void main(String[] args) {
Actress a = new Actress();
a.setName("女演员");
Doctor d = new Doctor();
d.setName("女医生");
cut(b);
}
// 多态的第一种使用场景 : 在设计一个方法参数时, 尽量将参数设计为 `父类引用`, 因为父类引用可以接收所有的子类对象.
public static void cut(Person p) {
p.doSomething();
}
② 对象引用接收
public static void main(String[] args) {
// 多态的第二种使用场景 : 创建子类对象, 使用父类引用接收, 可以提高程序的维护性.
Person p = new Actress();
p.setName("女演员");
cut(p);
}
public static void main(String[] args) {
// 多态 : 父类引用指向了子类对象. (向上转型 )
Person p = new Actress();
p.setName("女演员");
cut(p);
}
public static void cut(Person p) {
p.doSomething();
// 特有行为 :
// 报错 : beFamouse() 方法没有在 Person 类中被定义. 因为 p 调用是 Person 类型的.
// 说明 : 编译器是根据 `对象` 的接收类型类寻找 `属性和方法` 的.
// 解决方法 : 对象类型 `向下转型`. 将父类引用转换为子类引用.
Actress a = (Actress) p;
a.beFamous();
}
注意:创建的对象与向下转型类型没有保持一致,编译时正常,运行时会报ClassCastException 类型转换异常
public static void main(String[] args) {
Person p = new Doctor();
p.setName("女医生");
cut(p);
}
public static void cut(Person p) {
p.doSomething();
// 向下转型的目的 : 为了调用子类特有的 `属性/方法`.
if (p instanceof Doctor) {
Doctor d = (Doctor) p;
d.temptationOfUniforms();
} else if (p instanceof Actress) {
Actress a = (Actress) p;
a.beFamous();
} else if (p instanceof Barber) {
Barber b = (Barber) p;
b.chasingGirls();
}
}
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写;
final class 类名 {
// 类体
}
修饰符(public/private/default/protected) final 返回值类型 方法名(){
// 方法体
}
**注意:**实例变量也可以被定义为 final,被定义为 final 的变量不能被修改。被声明为 final 类的方法自动地声明为 final,但是实例变量并不是 final
// 不可更改的属性就应该使用 final 修饰 (public static final 组合关系)
public static final double PI = 3.14;
① 如果一个类拥有抽象方法, 那么该类就必须被定义为 抽象类
,使用 abstract 关键字修饰.
② 抽象类不能实例化对象,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
③ 抽象类必须被继承,才能被使用
④ Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
// 抽象类
public abstract class Animal {
private String name;
// 抽象方法
public abstract void shout();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
抽象方法
. 使用 abstract 关键字修饰public abstract void eat();
① 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
② 接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
③ 接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
public interface DrugDetectable {
// 常量 (默认修饰符 : public static final)
int YEARS = 5;
// 抽象方法 (默认修饰符 : public abstract)
void drugDetection();
}
// 多实现
public class Dog extends Animal implements BlindGuidable, DrugDetectable {}
// 多继承
public interface Hockey extends Sports, Event{}
准备一台电脑
public class Computer {
public void run(){
System.out.println("run...");
}
public void useUSB(USB usb){
usb.open();
usb.close();
}
}
准备一个USB接口
public interface USB {
void open();
void close();
}
外接设备实现USB接口
public class Keyboard implements USB{
@Override
public void open() {
System.out.println("Keyboard open");
}
@Override
public void close() {
System.out.println("Keyboard close");
}
}
public class Mouse implements USB{
@Override
public void open() {
System.out.println("Mouse open");
}
@Override
public void close() {
System.out.println("Mouse close");
}
}
测试
public class TestComputer {
public static void main(String[] args) {
Computer computer = new Computer();
computer.run();
USB usb = new Mouse();
computer.useUSB(usb);
USB usb1 = new Keyboard();
computer.useUSB(usb1);
}
}