面向对象的三种主要特性:封装、继承、多态。
1.类与对象
1.1 类与对象的基本概念:
- 类是一个基本模板,代表着一个共性的特征集合。比如男人和女人都是人。
- 对象是具体的每个人,是类的实例,比如每个人都有不同的属性、技能。
1.2 类与对象的基本定义:
类的定义:
// 定义一个人的类
class Person {
String name;
int age;
String sex;
public void getInfo() {
System.out.println("姓名:" + name + ",年龄:" + age + ",性别:" + sex);
}
}
对象的定义:
Person xiaohong = new Person();
// 类名称 对象名称 = new 类名称();
xiaohong.name = "小红";
xiaohong.age = 18;
xiaohong.sex = "girl";
xiaohong.getInfo();
// 姓名:小红,年龄:18,性别:girl
2.封装性
上文1.2定义的类的属性,外部可直接修改,这是不符合实际业务开发逻辑的。因此,我们使用private关键字进行封装,将类的属性私有化,并定义相应的getter和setter方法,区分别获取属性、修改属性。
修改后的类和对象:
class Person {
private String name;
private int age;
private String sex;
public void setName(String newName){
name = newName;
}
public void setAge(int newAge){
age = newAge;
}
public void setSex(String newSex){
sex = newSex;
}
public void getInfo() {
System.out.println("姓名:" + name + ",年龄:" + age + ",性别:" + sex);
}
}
public class Test {
public static void main(String[] args){
Person xiaohong = new Person();
xiaohong.setName("xiaowang");
xiaohong.setAge(22);
xiaohong.getInfo();
}
}
// >> 姓名:xiaowang,年龄:22,性别:null
3.构造方法
构造方法是一种特殊的方法,它只在新对象实例化的时候调用。
定义原则:
- 方法名称与类的名称相同
- 没有返回值类型声明
- 构造方法可以重载
定义构造方法:
class Person{
public Person(){ // 构造方法,不必声明返回值类型
System.out.println("Hello");
}
}
构造方法核心作用:
将类对象实例化时设置属性的初始化内容。
class Person {
private String name;
private int age;
private String sex;
public Person(String n, int a, String s) {
setName(n);
setAge(a);
setSex(s);
System.out.println("姓名:" + name + ",年龄:" + age + ",性别:" + sex);
}
public void setName(String newName){
name = newName;
}
public void setAge(int newAge){
age = newAge;
}
public void setSex(String newSex){
sex = newSex;
}
public void getInfo() {
System.out.println("姓名:" + name + ",年龄:" + age + ",性别:" + sex);
}
}
public class Hello {
public static void main(String[] args){
Person xiaohong = new Person("xiaowang",22,"boy");
}
}
// >> 姓名:xiaowang,年龄:22,性别:boy
4. this关键字
4.1 访问类属性都要加上this
class Person {
private String name;
private int age;
private String sex;
public Person(String name, int age, String sex) {
setName(name);
setAge(age);
setSex(sex);
System.out.println("姓名:" + this.name + ",年龄:" + this.age + ",性别:" + this.sex);
}
public void setName(String newName){
this.name = newName;
}
public void setAge(int newAge){
this.age = newAge;
}
public void setSex(String newSex){
this.sex = newSex;
}
public void getInfo() {
System.out.println("姓名:" + this.name + ",年龄:" + this.age + ",性别:" + this.sex);
}
}
public class Hello {
public static void main(String[] args){
Person xiaohong = new Person("xiaowang",22,"boy");
}
}
// >> 姓名:xiaowang,年龄:22,性别:boy
4.2 调用本类方法
- 调用本类普通方法:
this.getInfo() - 调用奔类构造方法:
this()、this(a,b)
4.3 表示当前对象
this 指向当前对象
5. 继承性
5.1 继承的实现
class 子类 extends 父类 {}
- 子类又称派生类
- 父类又称超类(Super Class)
- 子类的构造方法中,可以通过super访问父类的构造方法和普通方法
- 子类的普通方法中,只能通过super访问父类的普通方法
5.2 继承的限制
限制1:Java不允许多重继承,只允许多层继承。
但是可以使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口
public interface A {
public void eat();
public void sleep();
}
public interface B {
public void show();
}
public class C implements A,B { }
限制2:子类继承父类时,对于所有的私有操作属于隐式继承,而所有的非私有操作属于显示继承
也就是说,子类要想访问父类的私有属性,必须通过getter和setter
限制3:在子类对象构造前一定会默认调用父类的构造(默认使用无参构造),以保证父类的对象先实例化,子类对象的后实例化
class Parent {
public Parent(){
System.out.println("父亲");
}
}
class Son extends Parent {
public Son(){
System.out.println("儿子");
}
}
public class Hello{
public static void main(String args[]){
new Son();
}
}
// >> 父亲
// >> 儿子
6. 覆写(Override)
class Parent {
public void fun(){
System.out.println("父亲");
}
}
class Son extends Parent {
public void fun(){
System.out.println("儿子");
}
}
public class Hello{
public static void main(String args[]){
Son son = new Son();
son.fun();
}
}
// >> 儿子
7. 多态性
多态性主要体现在:
方法的多态性:
- 重载:同一个方法名称,根据不同的参数类型及个数可以完成不同的功能
- 覆写:同一个方法,根据实例化的子类对象不同,所完成的功能也不同
对象的多态性:
- 向上转型:子类对象变成父类对象,格式:
父类 父类对象 = new 子类();自动转换 - 向下转型:父类对象变为子类对象,格式:
子类 子类对象 = (子类)父类实例;强制转换
对象多态性的作用:
在实际的开发中,对象向上转型的主要意义在于参数的统一,也是最为主要的用法,而对象向下转型指的是调用子类的个性化操作方法。
8. 抽象类
8.1 抽象类的定义
抽象方法是指没有方法体的方法,也就是声明方法时不加{},加上abstract声明。
拥有抽象方法的类属于抽象类。
抽象类只比普通的类多了抽象方法的定义,其他结构与普通类完全一样。
abstract class A {
public void fun() {
System.out.println("存在有方法体的方法!");
}
public abstract void print();
}
8.2 抽象类的使用原则
-
抽象类必须有子类,即每一个抽象类一定要被子类所继承。
-
抽象类的子类必须覆写抽象类中的全部抽象方法(强制子类覆写)。
-
依靠对象的向上转型概念,可以通过抽象类的子类完成抽象类的实例化对象操作。
abstract class A {
public void fun() {
System.out.println("存在有方法体的方法!");
}
public abstract void print();
}
class B extends A {
public void print(){
System.out.println("抽象类的子类");
}
}
public class Hello{
public static void main(String args[]){
A a = new B(); // 向上转型
a.print(); // 调用子类覆写过的方法
}
}
8.3 抽象类应用——模板设计模式
暂时接触不到,后期再来补充
9. 接口(暂不考虑JDK1.8对接口的影响)
接口是一个特殊的类,这个类里面只有抽象方法与全局变量。
interface A { // 定义接口
public static final String MSG = "YOOTK"; // 全局变量
public abstract void print(); // 抽象方法
}
9.1 接口的使用原则
- 接口必须有子类,此时子类可通过implements关键字实现多个接口
- 接口的子类(如果不是抽象类),必须要覆写接口中的全部抽象方法
- 接口的对象可以利用子类对象的向上转型进行实例化操作
interface A {
String MSG = "Hello";
public void print();
}
interface B {
public void get();
}
class X implements A,B {
public void print() {
System.out.println("A接口的抽象方法");
}
public void get() {
System.out.println("B接口的抽象方法");
}
}
public class Hello{
public static void main(String args[]){
X x = new X(); // 实例化子对象
A a = x; // 向上转型
B b = x; // 向上转型
a.print();
b.get();
System.out.println(A.MSG);
}
}
9.2 接口的应用-标准
9.3 接口的应用-工厂设计模式
工厂设计模式:客户端无需关注具体的子类,只需要关注如何取得接口对象并且操作。
如下面的Friut接口,定义了两个子类Apple和Orange覆写eat的方法,同时定义了一个Factory类,对外提供获取两个子类实例的接口,在main函数直接调用Factory.getInstance("apple")方法获取Apple的实例。
interface Fruit {
public void eat();
}
class Apple implements Fruit {
public void eat() {
System.out.println("吃苹果");
}
}
class Orange implements Fruit {
public void eat() {
System.out.println("吃橘子");
}
}
// 定义工厂类,提供获取两个子类实例的方法 getInstance()
class Factory {
public static Fruit getInstance(String className) {
if("apple".equals(className)){
return new Apple();
}else if("orange".equals(className)){
return new Orange();
}else{
return null;
}
}
}
public class Hello{
public static void main(String args[]){
Fruit f = Factory.getInstance("apple");
f.eat();
}
}
9.4 接口的应用-代理设计模式(Proxy)
代理设计就是指一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理
interface NetWork {
public void browse();
}
// 真实的上网操作
class Real implements NetWork {
public void browse(){
System.out.println("上网浏览信息");
}
}
// 代理上网
class Proxy implements NetWork {
private NetWork netWork;
public Proxy(NetWork netWork){
this.netWork=netWork;
}
public void check() {
System.out.println("检查合法性");
}
@Override
public void browse() {
this.check();
this.netWork.browse();
}
}
public class Hello{
public static void main(String args[]){
NetWork net = new Proxy(new Real());
net.browse();
}
}
9.5 抽象类与接口的区别
| 区别 | 抽象类 | 接口 | |
|---|---|---|---|
| 1 | 关键字 | abstract class | interface |
| 2 | 组成 | 构造方法 抽象方法 普通方法 static方法 常量 变量 | 全局常量 抽象方法 |
| 3 | 子类使用 | class 子类 extends 抽象类 | class 子类 implements 接口, 接口... |
| 4 | 关系 | 抽象类可实现多个接口 | 接口不能继承抽象类,却可以继承多个父接口 |
| 5 | 权限 | 可以使用各种权限 | 只可使用public权限 |
| 6 | 限制 | 单继承局限 | 没有单继承局限 |
| 7 | 子类 | 都必须要有子类,子类必须覆写全部的抽象方法 | |
| 8 | 实例化对象 | 均依靠子类对象的向上转型进行对象的转化 |
10. 匿名内部类
匿名内部类是没有名字的内部类,其必须在抽象类或接口基础上才可以定义。
interface Message{
public void print();
}
public class Hello{
public static void main(String args[]){
fun(new Message() { // 直接实例化接口对象,无需创建一个类
@Override
public void print() { // 匿名内部类中覆写print()方法
System.out.println("Hello");
}
});
}
public static void fun(Message msg){
msg.print();
}
}