JAVA_OOP笔记[完结]

概念

面向对象(Object-Oriented Programming Concepts)是一种编程思想,强调的是结果。把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。
Oracle文档

面向对象与面向过程

面向对象和面向过程是两种软件开发方法,或者说是两种不同的开发范式。

什么是面向过程?

“面向过程”(Procedure Oriented)是一种以过程为中心的编程思想,是一种自顶而下的编程模式。
最典型的面向过程的编程语言就是C语言。

概述

把问题分解成一个一个步骤,每个步骤用函数实现,依次调用即可。
就是说,在进行面向过程编程的时候,不需要考虑那么多,上来先定义一个函数,然后使用各种诸如if-else、for-each等方式进行代码执行。
最典型的用法就是实现一个简单的算法,比如实现冒泡排序。

什么是面向对象?

面向对象程序设计的雏形,早在出现在1960年的Simula语言中,当时的程序设计领域正面临着一种危机:在软硬件环境逐渐复杂的情况下,软件如何得到良好的维护?
面向对象程序设计在某种程度上通过强调可重复性解决了这一问题。
目前较为流行的面向对象语言主要有Java、C#、C++、Python、Ruby、PHP等
面向对象是一种将事务高度抽象化的编程模式

概述:

将问题分解成一个一个步骤,对每个步骤进行相应的抽象,形成对象,通过不同对象之间的调用,组合解决问题。
就是说,在进行面向对象进行编程的时候,要把属性、行为等封装成对象,然后基于这些对象及对象的能力进行业务逻辑的实现。
比如:想要造一辆车,上来要先把车的各种属性定义出来,然后抽象成一个Car类。

引自:http://hollischuang.gitee.io/tobetopjavaer/#/basics/object-oriented/object-oriented-vs-procedure-oriented

特征

封装

封装属性思路

  1. 用private 修饰资源
  2. 提供公共的get方法,用来获取值
  3. 提供公共的set方法,用来设置值

封装方法思路

  1. 用pirvate 修饰方法
  2. 用本类的公共方法调用这个封装方法的功能

权限修饰符

官方文档
在这里插入图片描述

匿名对象

当被调用的对象只调用一次时(多次会创建多个对象浪费空间)

new Scanner(System.in).nextInt();

成员方法

  • 如果方法的返回值类型不是void,就需要使用return 关键字返回对应类型的返回值。

继承

多态

类和对象

类(class、type类型)

定义

对象

定义

  • 具体的实例,根据类具体创造出来的具体的实例

构造方法

定义
  • 特殊的方法,方法名与类名一致,没有返回值类型 官方文档
  • 可以使用四种权限修饰符
  • 每次new对象时,都会自动触发对应类中的构造方法
  • 无参构造每一个类中都会默认存在一个没有参数的构造方法,但是如果提供了其他的构造函数,则默认的无参构造会被取消
  • 含参构造含有参数的构造函数,可用于使用简单属快速创建对象,仅提供有限个数的属性值 ,其他的属性可以提供默认值。对参数也没有任何要求
  • 全参构造
    此构造函数与本类的属性一致,可用于初始化本类所有的属性

You don’t have to provide any constructors for your class, but you must be careful when doing this. The compiler automatically provides a no-argument, default constructor for any class without constructors. This default constructor will call the no-argument constructor of the superclass. In this situation, the compiler will complain if the superclass doesn’t have a no-argument constructor so you must verify that it does.

格式

与本类类名同名,且没有返回值类型的方法

构造代码块

格式

{构造代码块} 使用大括号包裹

位置

类里方法外,与其他成员并列, 主要用于抽取构造函数中共性的部分

执行时机

每次创建对象时都会执行构造代码块,且优先于构造函数执行

作用

用于提取所有构造方法的共性功能

局部代码块

格式

{局部代码块} 使用大括号包裹

位置

方法里面

执行时机

调用本局部代码块所处的方法时,才会执行

作用

限定局部变量的作用域,局部代码块中的局部变量只能在代码块里面使用

总结

执行顺序:构造代码块->构造方法->普通方法->局部代码块,分析:

  1. 当创建对象时,会触发构造函数
  2. 创建对象时也会触发构造代码块,且会优先于构造方法执行、
  3. 创建好对象后才能通过对象调用普通方法
  4. 如果普通方法里面有局部代码块,才会触发对应的局部代码块

this 关键字

  • 用于访问成员变量:当成员变量与局部变量同名时,可以使用this关键字来指定使用的是本类的成员变量。否则将根据就近原则来取值。
  • 用于访问构造函数:this(参数列表)必须在构造函数的第一行,普通方法不能使用此语句。构造函数形成死循环时会报Recursive constructor invocation编译错误
    this();用于调用本类无参构造
    this(参数);用于调用本类含参构造

继承

概念

继承是面向对象最显著的一个特征
继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并扩展新的能力

特点
  1. 使用extends关键字来表示继承关系,是is-a的关系,格式: son extends father
  2. 相当于子类把父类的功能复制了一份
  3. Java只支持单继承,一个子类只能有一个父类,但是一个父类可以有多个子类。
  4. 父类的私有成员也会被继承,但由于是私有的不可见,所以子类不能使用父类的私有资源。这一点可以在idea中使用debug功能跟踪看到子类确实继承了父类的私有资源,但是没有访问权限,会报错'b' has private access in 'cn.tedu.oop2.Cat'
  5. 继承多用于功能的修改,子类可以在拥有父类功能的同时,进行功能拓展
  6. 继承具有传递性,爷爷的功能会传递给父类,父类的功能会传递给子类
  7. 子类可以拥有自己的独有的方法,实现了功能的拓展,青出于蓝而胜于蓝
  8. 构造方法不可以被继承!因为语法的原因,构造方法的名称要与类名一致,不能在子类中出现一个父类名称的构造方法
  9. 如果一个类没有明确指定父类,则其默认继承自顶级父类Object,其构造函数中默认的super()调用的就是Object的无参构造

If your class has no explicit superclass, then it has an implicit superclass of Object, which does have a no-argument constructor.

super

  • 当父类的成员变量与子类的变量同名时,使用super指定父类的成员变量
  • 可以把super“看作”是父类对象的引用,但实际并不完全是一个父类对象
  • 子类在创建对象时,默认会先调用父类的构造方法,原因是子类构造函数中的第一行默认存在super();表示调用父类的无参构造
  • 子类必须调用一个父类 的构造函数,不论是无参还是含参,任选一个即可

重写

遵循的原则:两同两小一大
  • 两同:子类的 方法名参数列表与父类一致
  • 两小:子类返回值类型必须是父类方法返回值类型或其子类,void没有子类,所以重写时没得改。
  • 一大:子类方法的权限修饰符要大于或等于父类的
注解 @Override
  • 用来加在方法上,表示这是一个重写的方法。如果重写不成功,会报错

静态static

概念
  • java中的一个关键字
  • 用于修饰成员(变量和方法)
特点
  1. 可以修饰成员变量与成员方法
  2. 随着类的加载而加载到内存中,优先于对象加载,可以被类名直接调用,即使尚未创建对象。
  3. 只加载一次,就会一直存在,不再开辟新空间,直到类消失才会消失
  4. 静态资源,也叫做类资源,在内存中只有一份,全局唯一,被全局所有对象所共享。所以当通过任意一种方式修改了静态变量的值以后,不管用何种方式查看,静态变量的值都是刚刚修改过的值
  5. 被类名直接调用静态方法
  6. 普通资源可以调用普通资源和静态资源,静态资源只能调用静态资源。
  7. 静态区域是不允许使用this关键字的
  8. 静态方法不存在重写
  9. 如果子类中的与父类同名的静态方法output方法没有static修饰,则会报不能重写的编译错,所以static可以这样来解释:加上static是隐藏了父类中的方法,而不是重写。同样的,如果父类中的方法不是静态的,那么子类中的同名方法也不可以是静态的,也就是说静态的方法不能被覆盖,静态的方法也不能覆盖非静态的,总之一句话:静态的都不能覆盖,要么全静态,要么全非静态。参考连接

静态代码块

格式
static{
	code;
}
位置

与构造代码块并列,也是类里方法外

执行时机

静态代码块也属于静态资源,随着类的加载而加载,优先于对象加载,并且只加载一次

作用

用于加载那些需要第一时间加载,并且只加载一次的资源,常用来初始化。

final关键字

  1. final可以用来修饰类,被修饰的类是最终类,不可以被继承
  2. 可以把被final修饰的类看成是叶子节点
  3. final可以用来修饰方法,被修饰的方法是该方法的最终实现,不可以被重写
  4. 被final修饰的是常量,常量的值不可以被修改。注意:不论是成员位置还是局部位置,常量定义的时候必须赋值。名称一般全部大写,单词与单词之间使用_分隔。编译后所有的常量都被替换成了字面值。
  1. 【强制】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
    正例:MAX_STOCK_COUNT / CACHE_EXPIRED_TIME
    反例:MAX_COUNT / EXPIRED_TIME
  1. 修饰引用类型的变量时,该变量不能再指向其他的对象,但是所指向对象的自己的成员属性等可以更改

多态

概念

父类的引用指向子类的对象

所谓多态就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。
https://hollischuang.gitee.io/tobetopjavaer/#/basics/object-oriented/characteristics

只有普通方法或是抽象方法由于可以被重写,所以存在多态现象,其他的成员调用时是根据引用类型变量的类型来绑定的。
解释:如果是父类的引用传入的是子类的对象,当使用这个父类的引用调用父类里面定义的静态方法时,执行的就是父类里面的方法,即使子类也写了一个一模一样的方法也是如此。如果直接定义的就是子类对象,调用的是父类的静态方法而子类自己没有定义时,执行的就是从父类那里继承来的方法。如果子类也写了一个一模一样的方法,则执行的就是子类自己的方法了。
对于如下子父类关系

class A{
	public static void make(){}
}
class B extends A{
}

有如下的绑定

造型子类无make()子类声明了同样的make()
A a = new B();a.make();执行A.make();执行A.make();
B b = new B();b.make();执行A.make();执行B.make();
前提

继承、方法的重写

父类对象不可以使用子类的特有功能

口决
  1. 父类引用指向子类对象。【解释:创建出来的子类对象的地址值,交给父类类型的引用类型变量来保存】
Father f = new Son();// 这里的f就是父类类型的引用变量,但实际new的是子类的对象
  1. 编译(保存)看左边,运行看右边。方法定义看父类,方法体如果有重写的话使用子类的。
  • 【解释:必须要在父类定义这个方法,才能通过编译,把多态对象看作父类类型,必须要在子类重写这个方法才能满足多态:实际干活的是子类】
  • 此处的编译看左边是指在ide里面的时候,并不是指编译后,实际编译后前面的引用会被修改为后面new的类型的引用
  • Father father = new Son(); 编译后会被优化成 Son son = new Son();
Father father = new Son();// 定义引用变量f为父类类型
father.eat();// 假设父类里面有定义eat()方法,则此处没问题,否则报“Cannot resolve method 'eat' in 'Father' ”错误
  1. 成员变量看引用【当使用 father.sum这样的形式来访问成员变量时,取值是看引用的,引用是哪个类型,就用哪个类型声明或是其最近父类的声明的变量】
  2. 静态方法不存在重写情况,调用时看引用。引用是哪个类型的,就调用哪个类里面定义的静态方法

异常

异常是一些用来封装错误信息的对象
它由异常的类型、提示信息、报错的行号提示三部分组成
在这里插入图片描述

异常的处理
  • 自己捕获
try{
	可能会抛出异常的代码
} catch(异常的类型 异常的名字) {
	捕获到异常后,进行处理的解决方案
}
  • 嵌套捕获,从上到下,异常的范围从小到大,或是最后再写范围大的异常,如本下面例子中,范围较精确的InputMismatchExceptionArithmeticException优先捕获,最后再捕获范围最大的Exception异常
  • finally{}是try-catch结构的第3个部分,这分不论是否捕获到异常,都一定会执行,所以常用来关流操作。
try {
    System.out.println("请输入除数");
    Scanner sc = new Scanner(System.in);
    int a = sc.nextInt();
    System.out.println("请输入被除数");
    int b = sc.nextInt();
    System.out.println("两数相除的结果:" + a / b);
} catch (InputMismatchException e) {
    System.out.println("请输入整数");
} catch (ArithmeticException e){
    System.out.println("除数不能为0");
} catch (Exception e) {
    System.out.println("出错了");
} finally {
	//这里的操作一定会执行,如果在上面就有了返回语句,那么返回的结果以及返回操作将被挂起,直到这里的代码执行完成后再继承挂起的操作
}
  • 向上抛出
  1. 将异常向上抛出,交给调用者来解决。在方法的小括号与大括号之间写throws 异常类型 ,如果有多个异常,使用逗号分隔即可。
public static void method() throws ArithmeticException, InputMismatchException  {}
public static void method1() throws Exception {}

  1. 如果一个方法向上抛出了异常,则谁调用此方法就由谁来处理这个异常,所以这里的处理也有两种方案,捕获解决或是继续向上抛出。但注意,一般会在main()方法调用之前将异常解决掉,而不是抛给main()方法,因为这会导致main()方法直接中止。
public static void main(String[] args) {
	handleExceptionMethod();//在main方法中调用已经把异常解决掉了的方法
}
// 此方法做为中间方法,先行把异常处理掉
public static void handleExceptionMethod() {
	try{
		method();
	} catch (Exception e) {
		e.printStackTrace();
	}
}
public static void method() throws Exception {}

抽象类

  1. 被abstract修饰的方法是抽象方法,没有方法体。也不能有方法体,否则报错Abstract methods cannot have a body
public abstract void play();
  1. 被abstract修饰的类是抽象类,如果一个类中包含了抽象方法,则这个类必须声明为抽象类
// 声明为抽象类
abstract class Animal{
    public void eat(){System.out.println("animal eat");}

	// 抽象方法
    public abstract void play();
}
  1. 当子类继承了抽象父类后,有两种解决方案,要么也声明成抽象类(不实现 或 只实现部分抽象方法)、要么实现从父类继承的所有的抽象方法,“父债子偿”
class Pig extends Animal{
	// 实现从父类那里继承过来的抽象方法
    @Override
    public void play() {}
}
  1. 抽象类不可以被实例化,不能创建对象。但是可以指向其普通子类
 Animal a = new Animal();// 会报错“'Animal' is abstract; cannot be instantiated”
 Animal a = new Pig(); // 可以指向已经实现了所有抽象的普通子类
  1. 抽象类也有构造方法,为了子类创建对象时使用,即super();
abstract class Animal2{
	// 为了被子类的构造函数使用super();
    public Animal2(){
        System.out.println("animal2's constructor");
    }
    public void play(){
        System.out.println("animal2.play()");
    }
}
class Pig2 extends Animal2{
    public Pig2(){
        super();
        System.out.println("pig's constructor");
    }
}
  1. 抽象类对类内部的成员不做限制,可以全是普通成员,也可以全部是抽象方法。因为抽象类不能被实例化,所以如果一个普通类不想被实例化,可以使用abstract来修饰。
// 定义成抽象类,表示不可以创建此类的对象
abstract class Car{
    String name = "car";// 可以定义成员变量
    public static final int CAR_WHEELS = 4;// 可以定义常量
   	// 可以定义普通方法
	public void start(){
        System.out.println("car is start");
    }
    // 可以定义静态方法
    public static void paint(){
        System.out.println("car's color changed");
    }
}

// 子类继承了十分钟任何抽象方法的抽象类后也无需实现任何方法
class BYD extends Car{
}

// 全部都是抽象方法的抽象类也是允许的
abstract class Phone{
    abstract void call();
    abstract void message();
}

接口

  • 定义:与之前学习过的抽象类一样,接口在Java中也是一种抽象类型,接口中的内容是抽象形成的需要实现的功能。更像是一种规则和一种标准,大家都要遵守的
  • 特点:
  1. 可以把接口理解成一个特殊的抽象类(但接口不是类!!!)
  2. 使用interface关键字来声明, 一个interface文件中只能有一个public interface且接口名字与文件名字一致。
public interface Inter{}
  1. 方法可以简写,默认都是被public abstract修饰的,可写可不写,一直都在。方法不可以被protectedprivate修饰
public interface Inter{
   void eat();
   public abstract void play();// Modifier 'abstract' and 'public' is redundant(冗余) for interface methods 
   private void teach();// 编译错误“Modifier 'private' not allowed here”
   protected void ready();// 编译错误“Modifier 'protected' not allowed here”
}
  1. 实现类使用implements关键字来定义所实现的接口。定义好要实现的接口,要么实现接口中所定义的所有方法,要么自己变成抽象类只实现部分或不实现接口中的方法。
public abstract class InterImpl implements Inter{
	@Override
	public void eat(){
		System.out.println("interimpl.eat()");
	}
}
  1. 接口与抽象类一样,不可以被实例化
Inter inter = new Inter();// 会报错“'Inter' is abstract; cannot be instantiated”
  1. 创建接口(父接口) -> 接口实现类(子实现类) -> 测试类
public class TestInter {
    public static void main(String[] args) {
    	// ③测试接口实现类,多态形式
        Inter inter = new InterImpl();
        inter.get();// 输出:InterImpl.get()
    }
}

// ①先定义接口
interface Inter{
    void get();
}

// ②创建实现类
class InterImpl implements Inter{
    @Override
    public void get() {
        System.out.println("InterImpl.get()");
    }
}
  1. 接口里面没有构造方法
interface UserInter{
    public User();// 编译错误:`Not allowed in interface`
}
  1. 接口中定义的是静态常量,默认被public static final修饰,可写可不写。
interface UserInter{
	int age = 10; // 等同于 public static final int age = 10;此处必须赋值
}
class UserInterTest{
	public static void main(String[] args){
		int age = UserInter.age;// 测试类中可以通过`接口名.成员`名访问此成员的值,说明是static 修饰的
		UserInter.age = 10; //编译错误:“Cannot assign a value to final variable 'name'”,说明是final修饰的
	}
}
  1. 接口可以继承接口,而且还可以多继承,也就是一个子接口继承多件父接口;一个类也可以实现多个接口;多个接口之间使用号分隔。
interface Inter1{

    void save();
    void delete();
}
interface Inter2 {
    void find();
    void update();

}
// 接口可以继承多个接口
interface Inter3 extends Inter1,Inter2{
    void showTable();
}
// 一个类可以多实现
class Inter3Impl implelements  Inter1,Inter2{
	@Override
    public void save() {}

    @Override
    public void delete() {}

    @Override
    public void find() {}

    @Override
    public void update() {}
}
  1. JDK8中接口可以被default修饰的方法,并可以有方法体,该方法一般称作默认方法。与普通方法类似,可以重写,但重写时就不需要加defalt关键字
interface Info{
    default void play(){
        System.out.println("Info.play()");
    }
    default void eat(){
        System.out.println("Info.eat()");
        show();
    }
    void  show();
}
  1. 可以有静态方法,public可以省略,但是static是不可以省略的。调用时只能通过接口名调用,向上造型、子类类名、子类对象均无法调用 。
public interface Inter {
    public static void eat() {
        System.out.println("Inter.eat()");
    }
}
  • 接口与抽象类的区别
抽象类接口
使用abstract class关键字使用interface关键字
可以定义成员变量只有常量,默认public static final
对成员方法没有限制只有抽象方法public abstract
不可实例化不可实例化
有构造方法没有构造方法
只能单继承可以多继承
抽象是后天重构的结果接口是先天设计的结果

内部类

class A {// outter class
	// create B object,visit !private field of B
	class  B{ // innner class
		// just  for class A
		// visit all field of A
	}
}
分类
  • 成员内部类:类里方法外
  • 局部内部类:方法里面
  • 匿名内部类:new Outter().find();只创建对象,但是不使用引用变量对其进行引用
特点
  1. 内部类的实例化方式
Outer.Inner inner = outer.new Inner();
inner.delete(); // 得到内部类的对象后,使用就与普通类一样了
System.out.println("sum:"+inner.sum); //获得内部类的非私有属性也是与普通类一样

2.内部类可以使用外部类的所有资源,包括私有资源

class Outer{
    String name;
    private int age;
    public void find(){
        System.out.println("outer's find();");
    }
   class Inner{
       int sum = 10;
       public void delete(){
           System.out.println("Inner ... delete();");
           System.out.println("outter's name:"+name); // 访问外部类的成员属性
           System.out.println("outter's age:"+age); // 访问外部类的私有资源
           find();  // 访问外部类的成员方法
       }
   }
}
  1. 外部类如果想要使用内部类的资源,必须先创建内部类的对象,然后通过内部类对象来调用 内部类的资源。外部类不能直接调用内部类的普通成员。
  2. 普通内部类不可以有静态成员
  3. 匿名内部类new Outer().new Inner().delete();
  4. 静态内部类:很少用。内部类可以直接被外部类的名字调用,创建静态内部类时,就不需要先创建外部类的对象了new Outer3.Inner3()。只访问静态内部类的成员时,外部类不会被加载
public class TestInner3 {
    public static void main(String[] args) {
        Outer3.Inner3 in = new Outer3.Inner3();// 可以直接new了
        in.eat(); // 调用对应的内部类的普通方法
        Outer3.Inner3.show(); // 静态内部类的静态方法可以通过静态方式调用
    } 

}
class Outer3{
    static class Inner3{
        public void eat(){
            System.out.println("outer3.inner3.eat()");
        }
        public static void show(){
            System.out.println("outer3.inner3.show()");
        }
    }
}
  1. 局部内部类:
  • 位置:方法里
  • 使用 :直接调用内部类所在方法是无法触发内部类里面的功能的,需要所在方法里面、类声明的后面创建此内部类的对象,然后调用对应的功能。
public class TestInner4 {
    public static void main(String[] args) {
        new Outer4().show();
    }

}
class Outer4{

    public void show(){
        System.out.println("outer4.show();");

        class Inner4 {
            String name;
            int age;
            public void eat(){
                System.out.println("inner4.eat()");
            }
        }
		// 只有在内部类的声明后面才可以创建内部类的对象
        Inner4 in = new Inner4();
        in.eat();
    }
}
  1. 匿名内部类没有名字 ,通常与匿名对象结合在一起使用,匿名对象只双脚使用一次,一次只能调用 一个功能,匿名内部类充当了实现类的角色,去实现接口/抽象类中的抽象方法,只是没有名字而已。
  2. new Outer(){此处相当于是一个继承了前面对象的子类的类定义区域}.method();这种写法适用于接口、抽象类和普通类,大括号里面相当于是继承了前面的类。如果里面需要临时使用外面的局部变量,需要保证此变量为实际意义上的不可变,才可以通过编译,否则会报Variable 'id' is accessed from within inner class, needs to be final or effectively fina
int id = 10;// id赋值后不可以再次改变其值,否则会报编译错误“Variable 'id' is accessed from within inner class, needs to be final or effectively final”
new Inter2(){
	@Override
	public void set() {
	    System.out.println("id:"+id);
	}
}.set();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水晶心泉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值