面向对象

邮差的信 提交于 2019-12-01 05:10:21

面向对象笔记总结,随时查询

面向对象

类和对象

类是抽象的,是一个模板,确定对象将会拥有的特征(属性)和行为(方法)

对象是实体,是类的实例表现

属性和方法

属性:对象具有的各种静态特征

方法:对象具有的各种动态行为

命名

包的命名为域名小写字母的倒序加上功能名

类名首字母要大写

实例化对象

12345678
public class  {    String name;    public void run() {        System.out.println("run");    }}
12345
public static void main(String[] args) {    Cat one = new Cat(); // 声明并实例化对象    System.out.println(one.name); // 获取类中的对象    one.run(); // 获取类中的方法}

new

每次new都会开辟一个新空间,不会相互影响

123
Cat one = new Cat(); Cat two = one; // 此时one和two都指向通过一个堆内地址,会相互影响

构造方法

  1. 构造方法与类同名但是没有返回值
  2. 在对象实例化的时候调用
  3. 一个类中可以有多个构造方法

无参构造方法

不写构造方法,系统默认创建一个无参构造方法,自己创建带参构造方法,系统将再自动创建无参构造方法,需要自己手动创建

带参构造方法

将参数传递给类,进行属性的赋值

this

在构造函数中,可以将参数赋值给类中的属性,解决不能重名的问题

谁调用,this就指向谁(one调用,所以this执行one)

123
Cat(String name) {    this.name = name;}

在类中也可以通过this,在方法中调用另一个方法

this()写在第一行可以在带参构造函数前,调用无参构造函数

封装

只能通过规定的方法访问

隐藏类的实例细节,方便修改和实现

实现步骤

  1. 将属性的可见性修改为private
  2. 添加get/set方法
  3. 可以在get/set方法中添加过滤信息,如果使用了过滤信息,可以在构造函数中使用set进行赋值操作,避免传入参数类型有误

static

  1. 类中的属性设置static,通过这个类创建的所有对象将共用这个属性
  2. 类中的静态成员,可以通过对象名类名访问,推荐使用类名访问
  3. 静态方法中不能直接访问非静态成员(属性和方法),只能调用静态成员,除非实例化一个对象,通过对象调用,子类无法重写静态方法
  4. 普通方法可以直接访问类中的静态方法
  5. 普通代码块,方法之间的代码块,顺序执行
  6. 类中的代码块叫构造代码块,构造代码块将在构造方法之前执行,多个构造代码块按顺序执行
  7. 静态代码块,就是在构造代码块前添加static,静态代码块优先于构造代码块执行
  8. 静态代码块只会在类加载时执行一次

继承

继承是一种类与类之间的关系

使用已存在的类作为基础建立新的类

新类可以增加新的数据或新的功能,也可以用父类的功能,但是不可以选择继承父类中的属性或功能

继承的实现

子类可以调用父类中的方法使用父类中的方法,父类不可以使用子类

12
public class Animal { // 父类}
12
public class  extends Animal { // 子类}

方法重载和方法重写

子类可以重写父类中的方法

方法重载:

  • 同一个类中
  • 方法名相同,参数类表不同(参数顺序、个数、类型)
  • 方法返回值和访问修饰符任意
  • 与方法参数名无关

方法重写:

  • 有继承关系的子类中
  • 方法名相同,参数类表相同(参数顺序、个数、类型),方法返回值相同(如果父类返回值是父类类型Animal,子类返回值是子类类型Cat,也可以)
  • 访问修饰符,访问范围要大于等于父类访问修饰符
  • 与方法参数名无关

访问修饰符

  • private 只允许在本类中访问
  • public 允许在任意位置访问
  • protected 允许在当前类,同包子类/非子类、跨包子类调用调用,跨包非子类不允许
  • 默认 允许在当前类,同包子类/非子类调用,跨包子类/非子类不允许

super

可以通过super.xxx在子类中调用父类的属性或方法

子类构造函数默认调用父类的无参构造,可以通过super()调用父类的中允许被访问的其他构造

super()必须放在子类构造方法有效代码第一行

super和this

  • 都不可以在静态方法中使用
  • this是调用当前类中的属性或方法,super是调用父类中的属性或方法
  • super()和this()只能出现一个,因为都是要在代码第一行才有效

继承初始化顺序

父类静态成员-》子类静态成员-》父类对象构造-》子类对象构造

Object

equals()

  • 继承Object中的equals方法时,比较两个引用是否指向同一个对象
  • 子类可以通过重写equals方法的形式,改变比较内容,String中默认重写该方法,比较值是否相同

toString()

  • 输出对象名,默认调用toString
  • 继承Object中的toString方法时,输出对象的字符串表示形式:类型信息+@+地址信息
  • 子类可以通过重写toString方法的形式,改变输出内容,String中默认重写该方法,输出字符串

final

添加final,表示不能被继承

123
public final class Animal {} // 第一种final public class Animal {} // 第二种

方法添加final,表示不能被子类重写,但可以正常被子类调用

类中的属性添加final,只有在定义时构造方法中构造代码块中才能进行赋值

基本数据类型添加final,表示在使用前先赋值,一旦赋值不可修改

引用数据类型添加final,表示不能修改引用对象,但可以修改引用对象的值

配合static使用表示在全局中只加载一次且不可修改,可以用在配置文件

1
public static final String URL = "http://xxx";

注解

  • 源码注解 -》 只有源码中存在的注解,给编译器看,编译成class文件不存在
  • 编译时注解 -》 编程成class文件,依然存在的注解
  • 运行时注解 -》 在运行时会产生作用的注解

通过@Override注解表示重写父类中的方法

单例模式

  1. 只提供私有的构造方法
  2. 含有一个该类的静态私有对象
  3. 提供一个静态的公有方法用于创建、获取静态私有对象

饿汉式

创建对象实例的时候直接初始化,所以调用时速度快,但是因为在创建时已经创建,但是比较占据空间,就是用空间换取时间

123456789101112
public class SingletonOne {    // 1.创建类中私有构造    private SingletonOne() {}    // 2.创建该类型的私有静态实例    private static SingletonOne instance = new SingletonOne();    // 3.创建共有静态方法返回静态实例对象    public static SingletonOne getInstance() {        return instance;    }}

懒汉式

类内实例对象创建时并不直接初始化,知道第一次调用get方法时,才完成初始化操作,用时间来换取空间

123456789101112131415
public class SingletonTwo {    // 1.创建类中私有构造    private SingletonTwo() {}    // 2.创建该类型的私有静态实例    private static SingletonTwo instance = null;    // 3.创建共有静态方法返回静态实例对象    public static SingletonTwo getInstance() {        if (instance == null) {            instance = new SingletonTwo();        }        return instance;    }}

使用场景

  1. 创建对象时占用资源过多,但同时又需要用到该类对象
  2. 对系统内资源要求统一读写,如配置信息
  3. 当多个实例存在可能引起程序逻辑错误,如号码生成器

多态

  • 满足继承关系
  • 父类引用指向子类对象

向上转型

向上转型、隐式转型、自动转型 -> 父类引用子类实例(小类转向大类)

可以调用子类重写父类的方法已经父类的派生的方法,无法调用子类独有的方法

注:父类中的静态方法无法被子类重写(static方法无法被子类重写),所以向上转型后,只能调用父类原有的静态方法

12
Animal two = new Cat();Animal three = new Dog();

向下转型

向下转型、强制类型转换

子类引用指向父类对象,此处必须进行强转,可以调用子类特有的方法

必须满足转换条件才能强转,使用instanceof进行判断是否满足强转条件

123
Cat temp = (Cat)two;temp.run();temp.eat();
1234567891011
if (two instanceof Cat) {    Cat temp = (Cat)two;    temp.run();    temp.eat();}if (two instanceof Dog) {    Dog temp2 = (Dog)two;    temp2.sleep();    temp2.eat();}

类型转换实例

12345
Master master = new Master();Cat cat = new Cat();Dog dog = new Dog();master.feed(cat);master.feed(dog);

方法一、根据传入不同的类型,调用不同的方法

123456789
public void feed(Cat cat) {    cat.eat();    cat.playBall();}public void feed(Dog dog) {    dog.eat();    dog.playBall();}

方法二、传入动物的父类,方法中通过类型转换,调用子类的方法

1234567891011
public void feed(Animal obj) {    if (obj instanceof Cat) {        Cat temp = (Cat)obj;        temp.eat();        temp.playBall();    } else if (obj instanceof Dog) {        Dog temp = (Dog)obj;        temp.eat();        temp.playBall();    }}

抽象类

不允许实例化,可以通过向上转型,指向子类实例

父类只知道子类应该包含怎样的方法,但无法准确知道这些子类如何实现这些方法,可以使用抽象类

1
public abstract class Animal {}

抽象方法

不允许包含方法体子类中需要重写父类的抽象方法,否则,子类必须是抽象类

抽象方法要写在抽象类中

staticfinalprivate不允许和abstract并存

1
public abstract void eat();

接口

接口定义了类需要遵守的规范

接口不关系类的内部数据,也不关系类中方法实现的细节,只规定类中必须提供某些方法

习惯将接口命名以大写I打头

1234
IPhoto ip = new FourthPhone();ip.photo();ip = new Camera();ip.photo();
123456789
public interface IPhoto {    // 接口中的抽象方法可以省略abstract    // 默认访问权限为public,可以省略    void photo();      // 接口中的常量可以省略public static final    // 接口中常量和实现类中常量名相同,使用接口引用指向实现类,则调用的是接口中的常量    int TEMP = 20;}
123456
public class Camera implements IPhoto {        public void photo() {        System.out.println("相机拍照");    }}
123456
public class FourthPhone implements IPhoto {        public void photo() {        System.out.println("手机拍照");    }}

jdk1.8后可以在接口中写默认方法和静态方法

1234567
default void connection() { // 在调用接口的类中不是必须被实现,可以被重写    System.out.println("默认连接");}static void stop() { // 通过接口.stop调用    System.out.println("接口静态方法");}

如果接口中方法名相同,那么实现类中要重写该方法

如果接口和父类方法名相同,默认调用父类方法,无需重写(常量父类不会默认调用,要在实现类中进行实现)

接口可以多继承

内部类

成员内部类

  1. 内部类在外部使用时,无法直接实例化,需要借由外部类信息才能完成实例化
  2. 内部类的访问修饰符,可以任意,但是访问范围会受到影响
  3. 内部类可以直接访问外部类的成员,如果同名,优先访问内部类中定义的
  4. 可以使用外部类.this.成员的方式,访问外部类中的同名的信息
  5. 外部类访问内部类信息,需要通过内部类实例,无法直接访问
12345678910111213141516
public static void main(String[] args) {    Person lili = new Person();    lili.age = 20;  		// 1. new 外部类.new 内部类    Person.Heart myHeart = new Person().new Heart();    System.out.println(myHeart.beat());		    // 2. 外部类对象.new 内部类    myHeart = lili.new Heart();    System.out.println(myHeart.beat());    // 3. 外部类对象.获取方法    myHeart = lili.getHeart();    System.out.println(myHeart.beat());}
12345678910111213141516171819
public class Person {    public int age;    public Heart getHeart() {        return new Heart();    }    public void eat() {        System.out.println("eat");    }    public class Heart {        int age = 13;        public String beat() {            eat();            return age + "跳动";        }    }}

静态内部类

  1. 静态内部类中,只能直接访问外部类的静态成员,如果需要调用非静态成员,可以通过对象实例

  2. 静态内部类对象实例时,可以不依赖于外部类对象

  3. 可以通过外部类.内部类.静态成员的方式,访问内部类中的静态成员

  4. 当内部类属性与外部类属性同名时,默认直接调用内部类中的成员

    如果需要访问外部类中的静态属性,可以通过 外部类.属性 的方式

    如果需要访问外部类中的非静态属性,可以通过 new 外部类().属性 的方式

12345
Person.Heart myHeart = new Person.Heart();System.out.println(myHeart.beat());Person.Heart.say();System.out.println(Person.Heart.age);
123456789101112
public static class Heart {    static int age = 13;    public static void say() {        System.out.println("hello");    }    public String beat() {        new Person().eat();        return Person.age + "跳动";    }}

方法内部类

  1. 定义在方法内部,作用范围也在方法内
  2. 和方法内部成员一样,class前不可以添加publicpriivateprotectedstatic
  3. 类中不能包含静态成员
  4. 类中可以包含finalabstract修饰的成员
123456789101112131415
public Object getHeart() {    class Heart {        int age = 13;        public void say() {            System.out.println("hello");        }        public String beat() {            new Person().eat();            return Person.age + "跳动";        }    }    return new Heart().beat();}

匿名内部类

适用场景

  • 只用到类的一个实例

  • 类定义后马上使用

  • 给类命名并不会导致代码更容易理解

总结

  1. 匿名内部类没有类型名称、实例对象名称
  2. 无法使用private、public、protected、abstract、static修饰
  3. 无法编写构造方法,可以添加构造代码块
  4. 不能出现静态成员
  5. 匿名内部类可以实现接口也可以继承父类,但是不可兼得
12345678910111213141516171819202122
public class PersonTest {    public void getRead(Person person) {        person.read();    }    public static void main(String[] args) {        PersonTest test = new PersonTest();        test.getRead(new Person(){                        public void read() {                System.out.println("man");            }        });        test.getRead(new Person(){                        public void read() {                System.out.println("woman");            }        });    }}
12345678910111213141516
public abstract class Person {    private String name;    public Person() {    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public abstract void read();}

原文:大专栏  面向对象


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!