面向对象

6.面向对象-基础

  1、面向对象编程:OOP(Object-Oriented Programming,OOP)

  2、以类的方式组织代码,以对象的组织(封装)数据

  3、抽象

  4、三大特性:继承、封装、多态

  5、对象是具体的事务;类是抽象的(对对象的抽象);类是对象的模板

6.1类与对象的关系

类(现实对象的模板)是一种抽象的数据类型,对某一类事务整体描述/定义;但是不能代表一个具体的事务

  ·动物、植物、家电、、、、

  ·Person类、Pet类、Car类

  ·在一组相同或者类似的对象中,抽取出共性的特征和行为,保留所关注的部分

对象是抽象概念的具体实例

  ·张三是一个人的的具体实例

  ·能够体现出特点,展现出功能的具体实例,而不是抽象概念

  ·将对象保存在相同类型的实例名(对象名/引用名)变量中

·访问属性

 *   对象名.属性名 = 值; //赋值
 * 对象名.属性名 //取值
 调用方法:
 * 对象名.方法名();

 

6.2创建于初始化对象

  1、使用new关键字创建。分配内存空间+默认初始化+对类中构造器的调用

  2、构造器也成为构造方法,创建对象时必须调用;其特点:必须和类名相同;必须没有返回类型,也不能写void

 package com.oop.object;
 ​
 //学生类
 public class Student {
 ​
     //属性:字段
     String name;
     boolean sex;//1:boy 2:girl
     int age;
 ​
     //方法
     public void study(){
         System.out.println(this.name+"在学习");
    }
 }
 ​
 /**
  * public class Application {
  *     public static void main(String[] args) {
  *         //类是抽象的 需要实例化
  *         Student student = new Student();
  *         student.name = "Joey";
  *         student.sex=true;
  *         student.age=12;
  *         student.study();
  *     }
  * }
  * */

6.3构造器详解

  1、即使什么方法都不写,也存在一个默认的无参构造器;

  2、无参构造器可以实例化对象(值初始化)

  3、使用new关键字,本质实在调用构造器。

 package com.oop.object;
 ​
 public class Person {
     String name;
     //快捷键:alt+insert ==》生成构造器
     //显示定义(无参)构造器
     public Person(){
 //       this.name = "Joey";
    }
 ​
     //有参构造器 : 一旦定义了有参构造,无参构造必须显示定义
     public Person(String name){
         this.name = name;
    }
 }

6.4小结

1、类与对象;类是一个模板:抽象,对象是一个具体的实例

2、方法:定义&调用(避免方法死循环)

3、对象的引用:

  引用类型: 基本类型(8种)

  对象是通过引用来操作的:栈 ---》 堆

4、属性 :字段Field成员变量

默认初始化:

数字:0 0.0

charu0000

booleanfalse

引用:null

  修饰符 属性类型 属性名 = 属性值

5、对象的创建和使用

  -必须使用new关键字来创建(默认的无参构造器,自定义有参构造器(必须显示定义无参构造器))  

      Person p = new Person();

  -对象的属性 : p.name

  -对象的方法: p.hello()

6、类

  静态的属性 属性

  动态的行为 方法

7、局部变量(要求先赋值再使用,否则报未初始化错误)与实例变量区别

变量的属性局部变量成员变量(实例)
定义位置 方法或者方法内部结构当中 类的内部,方法的外部
默认值 字面值(与数组相同)
使用范围 从定义行、列到包含其结构结束 本类有效
命名冲突 不允许重名 可与局部变量重名(局部变量优先)

 

7.面向对象-三大特性

7.1封装

  封装:数据的隐藏

  程序设计追求“高内聚,低耦合”

  私有属性:get/set

封装的意义:  

  1、提高了程序的安全性

  2、隐藏代码的实现细节

  3、统一接口

  4、系统可维护性增强

 package com.oop.encapsulation;
 ​
 public class Student {
     //姓名
     private String name;
     //学号
     private int ID;
     //年龄
     private int age;
     //性别 1:boy 2:girl
     private boolean sex;
     //专业
     private String major;
 ​
     public String getName() {
         return name;
    }
 ​
     public void setName(String name) {
         this.name = name;
    }
 ​
     public int getID() {
         return ID;
    }
 ​
     public void setID(int ID) {
         this.ID = ID;
    }
 ​
     public int getAge() {
         return age;
    }
 ​
     public void setAge(int age) {
         this.age = age;
    }
 ​
     public boolean isSex() {
         return sex;
    }
 ​
     public void setSex(boolean sex) {
         this.sex = sex;
    }
 ​
     public String getMajor() {
         return major;
    }
 ​
     public void setMajor(String major) {
         this.major = major;
    }
 }

7.2继承

  Java中所有的类都默认直接或者间接继承Object类

  继承的本质是对某一批类的抽象

  extends是“扩展”;即子类是父类的扩展(子类会拥有父类的全部公共(public)方法)

  Java中只有单继承没有多继承(一个儿子可以有一个爸爸,一个爸爸可以有多个儿子)

  继承是类与类之间的关系,除了继承以外还有依赖、组合、聚合  

  继承关系的两个类,一个为子类(派生类),一个为父类(基类)

  Object类、super、方法重写

7.2.1 super详解

super注意点:

  1、super调用父类的构造方法,必须处于代码(构造方法)中的第一行

  2、super必须只能出现在子类的方法或者构造方法中

  3、super和this不能同时调用构造方法

VS this:

代表的对象不同:

  this:本身调用本类的对象

  super:代表父类对象的应用

前提:

  this:没有继承也可以使用

  super:只能在继承条件下才能使用

构造方法:

  this():本类的构造

  super():父类的构造

Person(父类)

 package com.oop.inherit;
 ​
 public class Person {
     //父类无参构造
     public Person(){
         System.out.println("父类无参构造");
    }
     //父类有参构造
     public Person(String name){
         System.out.println("父类有参构造");
    }
     //人的特性
     public void say(){
         System.out.println("Say Hello!!!");
    }
 ​
     protected String name = "Joey";
 ​
     public void print(){
         System.out.println("Person");
    }
 }

Student(子类)

 package com.oop.inherit;
 ​
 public class Student extends Person{
     public Student(){
         super();
         System.out.println("子类无参构造");
    }
     public Student(String name){
         System.out.println("子类有参构造");
    }
 ​
     private String name = "Rose";
 ​
     public void test(String name){
         System.out.println(name);//main中的参数名
         System.out.println(this.name);//Student类本类中的名字
         System.out.println(super.name);//父类中的名字
    }
 ​
     public void print(){
         System.out.println("Student");
    }
 ​
     public void test1(){
         print(); //当前类对象
         this.print(); //当前类对象
         super.print(); //父类对象
    }
 }
 /*
 * public class Application {
     public static void main(String[] args) {
         Student s = new Student();
         s.test("乔伊");
         s.test1();
     }
 }
 * */
 ​

7.2.2方法重写

  重写是方法的重写;与属性无关

重写注意点:

  1、需要有继承关系;子类重写父类的方法

  2、方法名必须相同

  3、参数列表也必须相同

  4、修饰符:范围可以扩大,但是不能缩小 public>protected>Default>private

  5、抛出的异常:范围可以被缩小,但是不能扩大:ClassNotFoundException --->Exception(大)

  6、子类和父类方法必须一致;方法体不同

为什么需要重写?

  1、父类的功能子类不一定需要

  2、Alt+Insert 选中Override(重写)

不能被重写的情况:  

  1、static 方法属于类,不属于实例

  2、final 常量 不能被重写

  3、private 方法不能被重写

B类(父类)

 package com.oop.inherit;
 ​
 public class B {
     public static void test(){
         System.out.println("B=>test()");
    }
 ​
     public void test1(){
         System.out.println("B=>test1()");
    }
 }
 ​

A类(子类)

 package com.oop.inherit;
 ​
 public class A extends B{
     public static void test(){
         System.out.println("A=>test()");
    }
 ​
     @Override  //注解:有功能的注释
     public void test1() {
 //       super.test1();
         System.out.println("重写B的test1");
    }
 }
 ​
 /*
 * public static void main(String[] args) {
         B b = new A();
         b.test1();
 ​
     }
 * */

7.3多态

  同一方法根据发送对象的不同而采用不同的行为方式

  动态编译:类型;可扩展性变强;屏蔽子类间的差异;灵活,耦合度低

多态存在的条件:

有继承关系

  子类重写父类的方法

  父类引用指向子类对象

  多态是方法的多态,属性没有多态性

多态的注意点:

  1、多态是方法的多态,属性没有多态

  2、父类和子类有联系,否则会有类型转换异常:ClassCastException

  3、存在的条件: 继承关系;方法需要重写;父类引用指向子类对象

  4、子类转为父类:向上转型

  5、父类转为子类:向下转型(需要强制转换)

  6、方便方法的调用,减少重复的代码!简介

 package com.oop.polymorphic;
 //父类
 public class Father {
     public void run(){
         System.out.println("Dad running!");
    }
 }
 ​
 package com.oop.polymorphic;
 ​
 public class Son extends Father{
     @Override
     public void run() {
         System.out.println("Son running!");
    }
 ​
     public void eat(){
         System.out.println("eating!");
    }
 }
 /*
 *   public static void main(String[] args) {
         Son s = new Son();
         Father f = new Son(); //父类的引用指向子类的对象
         Object o = new Son();
         
         s.run();
         f.run(); //子类重写父类方法,执行子类的方法
 ​
         //对象能够执行哪些方法,主要看对象左边的类型
         s.eat();
         ((Son) f).eat(); //强制转换f为Son类型
     }*/

7.3.1 instanceOf 类型(引用)转换

 public class Application {
    //instanceof 判断是否存在父子关系 是返回true 否则false
     public static void main(String[] args) {
         //Object > Father > Son
         //Object > String
         Object o = new Son();
 ​
         System.out.println(o instanceof Son);
         System.out.println(o instanceof Father);
         System.out.println(o instanceof Object);
         System.out.println(o instanceof String);
    }
 }
 /*
 *   public static void main(String[] args) {
         Son s = new Son();
         Father f = new Son(); //父类的引用指向子类的类型
         Object o = new Son();
 ​
         s.run();
         f.run(); //子类重写父类方法,执行子类的方法
 ​
         //对象能够执行哪些方法,主要看对象左边的类型
         s.eat();
         ((Son) f).eat(); //强制转换f为Son类型
     }*/

7.3.2多态的应用

  场景一:使用父类作为方法形参实现多态,使方法的参数类型更为宽泛

  场景二:使用父类作为方法返回值实现多态,使方法可以返回不同的子类对象

7.3.3装箱

  向上转换:父类引用中保存真实的子类对象,称为向上转型(多态核心)

                  Animal a = new Dog();

7.3.4插箱

  向下转型(拆箱):将父类引用中的真实子类对象,强行转换为子类本身类型,向下转型。

                  Dog dog = (Dog)a;

  向下转型之前,应该判断引用中的真实子类对象类型,保证类型转换的正确性

 

8.面向对象-补充

8.1抽象类(abstract)

  可以修饰方法(抽象方法)也可以修饰类(抽象类)

  抽象类中可以没有抽象方法;但是有抽象方法的类一定要声明为抽象类

  抽象类,不能使用new关键字来创建对象,用来让子类继承

  抽象方法:只有方法的声明,没有方法的实现,用来让子类实现的

  子类继承抽象类,必须实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类

 package com.oop.others;
 ​
 //该类为抽象类
 public abstract class Action {
 ​
     //抽象方法 只有方法的约束 没有方法体
     public abstract void doSomething();
     /*
     * 1、不能new抽象类,只能靠子类取实现它:约束
     * 2、抽象类中可以写普通的方法
     * 3、抽象方法必须在抽象类中
     * */
 }
 ​
 package com.oop.others;
 ​
 //abstract 抽象类; 类 extends:单继承(接口可以实现多继承)
 //子类继承抽象类,必须实现抽象类中所有的方法;除非子类也是一个抽象类
 public class A extends Action{
     public void doSomething() {
         System.out.println("继承抽象类A ");
    }
 }

8.2接口

interface

  普通类:只有具体实现

  抽象类:具体实现和规范(抽象方法)都有

接口:只有规范!自己无法写方法;约束和实现分离

  接口就是规范(定义的一组规则;本质==契约;面向对象(OO)的精髓)

作用

  1、约束(定义一些规则)

  2、定义一些方法,让不同的人实现

  3、默认方法:public abstract

  4、默认常量:public static final

  5、接口不能被实例化;接口中没有构造方法

  6、implements可以实现多个接口

  7、必须要重写接口中的所有的方法

                              与抽象类的异同:

相同点不同点
可编译字节码文件 所有属性都是公开静态常量,隐式使用public static final修饰
不能创建对象 所有方法都是公开抽象方法,隐式使用public abstract修饰
可以作为引用对象 没有构造方法和静态代码块
具备Object类中的所有定义的方法  

接口引用:

  类与类:单继承;extends 父类名称

  类与接口:多实现;implements 接口名称1,接口名称2,,,接口名称n

  接口与接口:多继承;extends 父接口1,2,3,,,,n

 package com.oop.others;
 ​
 //interface 接口的关键字
 //接口都需要实现类
 public interface UserService {
 ​
    //常量 默认:public static final
    public static final boolean sex = true;
    int age = 21;
 ​
    /*方法默认为 public abstract ;接口中所有的定义都是抽象的*/
    void run();
    void eat(String name);
 }
 ​

 

 package com.oop.others;
 ​
 public interface TimeService {
     void checkTime();
 }
 ​
 package com.oop.others;
 ​
 //抽象类:extends~
 //类 可以实现接口 implements 接口
 //重写接口里面的所有方法
 public class UserServiceImpl implements UserService,TimeService{  //多继承(利用接口)
 ​
     public void run() {
         System.out.println("running");
    }
 ​
     public void eat(String name) {
         System.out.println(name+"eating");
    }
 ​
     public void checkTime() {
         System.out.println("现在是北京时间:");
    }
 }

8.3内部类

特点:

  -编译后可以独立的生成字节码文件

  -内部类可以直接访问外部类的私有成员,而不破坏封装

  -可以为外部类定义必要的组件

一个类的内部在定义一个类

1、成员内部类

  -类的内部定义,与实例变量和实例方法同级别的类

  -外部类的一个实例部分,创建对象时,必须依赖外部类对象

  -当外部类和内部类存在重名属性,优先访问内部类属性

  -成员内部类不能定义静态成员

2、静态内部类

  -不依赖外部类对象,可直接创建或者通过类名访问,可声明静态成员

  -只能访问外部类的静态成员(实例成员需要实例化外部类对象)

3、局部内部类

  -定义在外部类方法中,作用范围和创建对象范围仅限于当前方法

  -局部内部类访问当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final

  -限制类的使用范围

4、匿名内部类

  -没有类名的局部内部类(其余特征与局部内部类相同)

  -必须继承一个父类或者实现一个接口

 package com.oop.inner;
 ​
 public class Outer {
 ​
     protected String sex;
     private int id = 10;
     public String name;
     public void out(){
         System.out.println("外部类方法输出");
    }
     public class Inner{
         public void in(){
             System.out.println("这是内部类的输出");
        }
         //获得私有属性
         public void getId(){
             System.out.println(id);
        }
    }
 }
 /*
 * public static void main(String[] args) {
         Outer outer = new Outer();
         //通过外部类实例化内部类
         Outer.Inner inner = outer.new Inner();
         inner.getId();
     }
 * */

 

原文地址:https://www.cnblogs.com/joey-413/p/13234845.html