一、面向对象OO:(类+对象)==表格

  1. 所有的数据,都可以看成是表格,只有静态和动态
  2. 以类的方式组织代码,以对象的方式组织(封装)数据。

1. 面向过程:执行者思维(简单问题)

  • 可视?
  • 步骤1,2,3…

2. 面向对象:设计者思维(复杂问题)

  • 先思考解决问题需要分哪些类,再对类进行单独思考,类中间是细节考虑的东西。
  • 面向对象包括(封装了)面向过程。
  • 不可视?
  • 协作问题。

二、类

  • 即:属性(私有)+方法(public、set、get)== 表的结构class
    静态类、模板、设计者
  • 包含一堆可以不同类型的变量。

1.定义、创建、初始化使用

  • 不是每一个创建的类都需要一个main()函数,只是单纯的需要一个方法,放置一堆对象,并且进行相关的操作。
  • 一个project一般只有一个main()函数。
public class Car {

}
class type{

}
  • p1、p2对象就是Person类的具体实例。
Person p1 = new Person();
        Person p2 = new Person();  
        System.out.println(p1.name);
  • 用new创建的情况下,刚刚创建好的对象,会进行①分配内存空间+②默认进行初始化(null、0、false)+③对类中构造器调用
p1.name = "小明";
        p1.age = 18 ;       //静态初始化

        System.out.println(p1.name+"\t"+p2.name);
        System.out.println(p1.age+"\t"+p2.age);

♥♥构造器:constructor四个要点:

  • 对对象的属性进行初始化工作。
  1. 关键词new来 调用:本质:调用构造器。(new 调用构造的方法)
  2. 有调用,有return返回值
  3. 构造器的方法、名称必须与类相同(大小写也得相同)
    方法:是公用的。
  4. 隐式构造出:如果没有定义该构造器,idea会自动定义添加一个 无参的 有初始值,没有返回值return,也不能写void 构造方法。(默认一个隐式参数,this)
    this.id指的是上面这个 类的id。
  • 定义有参构造之后,如果要使用无参构造,显示地定义一个无参的构造器。

三.对象object,instance

动态的、过程、方法。 是具体实例

  • 一个对象:包含上述类中的每一个变量。这么一片叫一个对象。
  • 可以有多个对象。

四、面向对象的内存分析 ♥

目的:理解对象

java虚拟机内存模型概念:

1.线程

  • 栈stack:连续的,动态的
    ①程序计数器:记录执行到哪一步,下次执行知道从哪里开始。
    ②java虚拟机栈:栈帧(JVM为每个线程创建一个栈)
    ③本地方法栈:操作系统
    ④main()在栈底

2.堆

  • heap(存数组):不连续的,新建的new
    划分不同分区,根据需求不同,分得不同的时间空间,(传值), 方便垃圾回收。
    (不动的)

3.方法区

  • 也属于jdk (堆),不连续的,静态的
  • 是一种java虚拟机的规范。(静态方法区:放一些不变的)
    (模板、不动的)

运行时常量池:
直接内存:可以直接去交互的内存块。


4.JVM回收垃圾

垃圾回收机制 GC:(garbege collection)

  • 自动回收(new的),回收没用的,赋值null即可。

垃圾回收算法:

①引用计数法:减减,至0时,回收。
循环引用的无用对象无法识别。
②引用可达法(根搜索算法):
找根,再找有应用到的节点,剩下的就是没有用过的节点,被GC掉。

5.分代垃圾回收机制:

①年轻代 Eden、Survivor(很少用的)

  • Minor GC:Eden(一起用完才清空);
    Survivor1,2(没请掉的到这里来);
    再清,清了15次还没清掉,丢到年老代去。

②年老代Tenured/Old(经常用的)

  • Major GC年老代;
    Full GC:全量回收,大扫除,全面清除掉所有我能控制的区域(年轻+年老)

③永久代(一直在用的)
与JVM共存亡。

  • JVM调优,很大部分对于Full GC,
    System.gc():“建议”启动垃圾回收,而不是调用运行。
    但是大部分都会接受建议。

6.this 、static关键字

  • this:创建好的对象的地址

a.this的常用用法:

  1. 产生了变量名字重名的歧义,可以用this表示当前对象。
    普通方法中,this指向调用该方法的对象;
    构造方法中,this指向正要初始化的对象。
  2. this关键字调用重载构造方法时,避免相同的初始化了。
    但只能在构造方法中用,并且位于构造方法的第一句
  3. this 不能用于static方法中。

b.static关键字:

  • 静态初始: 代码块前面加 static
    在静态初始化块中,不能直接访问非static成员

7.变量的分类

1.局部变量

方法或语句块内部声明;属于方法/语句块:从该方法开始,到这块执行完,变量消失。

2.成员变量(实例变量)

类内部,或者方法的外部声明;属于对象。对象创建,变量创建,随对象的消失变量一起消失。

3. 静态变量

在类内部声明,用static修饰;属于类。类被加载,静态变量就有效,随编译器的启动而启动,关闭而消失。所有都可以访问。

8.包机制

  • package:相当于文件夹
    开源的,起名有要求:用域名作用的名字。(域名倒着写)com.yuming.test…
  • com.yuming和com.yuming.com区别:逻辑上有父子关系但是实际上是两个完全独立的个体。

JDK中的主要包

核心包
1.java.lang:**String**、Math、Interger、System、Thread提供常用功能
(这个核心包可以不用导入就使用)
2.java.awt:集成窗口工具集的多个类,构造管理应用程序图形用户界面(GUI)(少用的)
3.java.net:执行类与网络相关的操作类
4.java.io:提供多功能输入/输出类
5.java.util:包含一些实用的工具类,如定义系统特性、使用与日期日历相关的类
import导入新的包♥
  • import . com. yuming .包名.*;
    不存在先后顺序。
  • 具体到导入某一个类:全部写进去;
  • 外面的其他包我都想要:不用具体到class,用 .* 表示;(会降低编译速度,不会降低运行速度)
    ···
  • Alt+Enter可以快捷键自动导入。

五、继承 extend

  • 私有属性(变量),共有方法(类),get、set方法获取。
  • get、set驼峰命名规则:alt+shift+insert自动生成
    意义:
  1. 提高程序的安全性,保护数据
  2. 隐藏细节
  3. 统一接口
  4. 提高系统的可维护性。(修改内部代码)

1.单继承

类与类的关系:

  • 类只有单继承:只有一个直接的父类
  • 接口有多继承

- 继承的实现:代码的复用

可以继承属性和方法。(扩展extends)
	class xxx extends yyy{
	}
  • 公共的public才可以继承,私有的不可以继承。
  • public、protected、default、private优先级依次往后。
  • 虽然可以继承所有属性和方法(父类构造法除外),但不一定所有的都可以直接访问(如私有属性)

2.组合

收购了,并购了。

this.person.name = dog;

3.继承和组合

都可以实现代码的复用。

  • 继承:is - a的关系
  • 组合:has-a的关系

(逻辑上的关系注意一下)


六、override 重写

  • 覆盖
  • 子类重新定义父类。(父类的引用指向了子类)√
    父类B 变量b 指向= 引用new子类 A();
    (方法的调用只和左边的有关)

1.重写的特点:

  1. 是父类和子类才有的(存在继承关系)。是子类重写父类的方法。
  2. 方法名必须相同。
  3. 参数列表必须相同。(否则是重载了)
    重载是名字或者参数列表有不一样。
  4. 修饰符:范围可以扩大,不能缩小:public最大,protected,default、private最小。
    (子类可以访问的范围更大,优于父类)
  5. 抛出异常:异常的范围可以被缩小, 但不能扩大。(继承之后一定变好了,不能越来越差了)

重写子类和父类的方法必须一致,方法体不同。

即符合:
	  ①“= =”:方法名、形参列表相同
	  ②”≥“:访问权限,子类大于等于父类
	  ③“≤”:返回值类型和声明异常类型,子类小于等于父类。

2.重写的原因:

  • 父类的功能:子类不是所有的都需要,也不是都满足需要。
    ALT+shift+INSERT : override

3.final关键字

  1. 修饰变量:被它修饰的变量不可改变。不可以重新被赋值
final	int MAX_SPEED = 120;
  1. 修饰方法:方法不能被重写,我的方法不可以被子类重新修改,但是可以被重载。(可以随便用,不可以改)
final void study(){
		}
  1. 修饰类:修饰的类不可以被继承(不需要子类了)。如Math、String。
final class A{
		}

4.object类:

  • 是所有java的父类(根)
  • 也就是:所有的除了构造类的都能被继承,但是不一定都能用。(如私有的就不能使用)
public class Person{
		...
	}//等价于以下:
	
	public class Person extends Object{
		...
	}
  • object类包括:
    hashCode();toString(); clone();getClass();notify(); wait(); equals();等…

1.toString方法

  • 可以自动调用返回值为String类型的方法;
  • s.toString(); 直接输出时,括号里面可以不写。
  • 可以重写toString。
  • toString()方法默认返回的字符串是: 对象+@+地址。

2.==号与equals方法

public boolean equals(Object obj){
		return (this == obj);
	}

是否与当前的hashcode一样。(两个对象是否相同)


3.super

  • 可以看作时直接父类对象的引用。可以用来访问父类中被子类覆盖的方法和属性。
- super的注意点:
  1. 所有的构造方法第一句总是super(…)或者this(…)。因此,自己不调用时,系统会自动调用无参的super();构造器。
  2. super调用父类的构造方法,必须在子类构造器的第一行
  3. super 必须只能出现在子类的方法或者构造方法中
  4. super和this不能同时调用构造方法!(因为super 和this 调用都得在第一行)
- super 和 this区别:
  1. 代表的对象不同
    this:本身调用者这个对象
    super:代表直接父类对象的应用
    前提:
  2. this:没有继承也可以使用(可以直接使用,默认的)
    super:只能在继承条件下可以使用
  3. 构造方法:
    this(); 当前本类的构造
    super();直接父类的构造

七、封装encapsulated

  • 实现高内聚,低耦合。(封装类的内部细节,便于修改内部代码,而不许外部干涉,提高可维护性;简化外部调用,便于调用者使用,便于扩展和协作。)

1.访问控制符

  • 从而实现封装

1.private

私有,只有同一个类可以访问。

2.default

没有修饰符修饰,只有同一个package的类可以访问。(一个包中多个类都可以访问)

3.protected

可以被同一个包的类以及其他包中的子类访问。(同类+同一个包的不同类+不同包的子类)

注意:♥

  1. 父类和子类在同一个包中时,子类可以访问父类的protected成员,也可以访问父类对象的protected成员。
  2. 父类和子类不在同一个包中时,子类可以访问父类的protected成员,但是不能访问 父类对象的protected成员。

4.public

所有类都可以使用,只要是这个project就可以使用。

2.封装的使用细节

简单规则:

  1. 属性:一般使用private访问权限
  2. 属性私有后,提供相应的get/set方法来访问相关属性,这些方法通常是public修饰。(Boolean 变量的get方法是is开头的)
  3. 方法:一些只用于本类的辅助性方法可以用private修饰。
    有需要其他类调用的方法public修饰。

八、多态polymorphism

  • 方法的多态:同一个方法的调用,对象的不同行为引起的。= =重写 override(方法体)
  • 一个类的实际对象是确定的,但是可以指向这个对象的 引用类型是任意的:他的本类、父类、祖宗object等等都可以引用同一个类。
Student s1 = new Student();
Person s2 = new Student();
Object s3 = new Student();
  • 右边的为实际对象。能执行的方法组要看左边的类型,和右边关系不大。左边有才可以用。

1.对象的转型

case转

  • 而父类是不可以调用子类后面的私有方法。
  • 高转低的话,可以强制类型转化。

- 多态的注意:

  1. 多态是方法的概念,属性没有多态。(override的本质)
  2. 父类与子类之间继承关系时,才可以强制类型转换。
    不相关无联系的类时如果强制转化:异常报错:ClassCastException!
  3. 存在的条件
    ①是继承关系,
    ②方法需要重写。
    ③父类的引用指向子类对象。Father f1 =指向 new son();
- 不可以被重写的:
  1. static
  2. final
  3. private

也就不存在多态。


2.抽象方法和抽象类

  • 抽象方法:就是一种声明
    使用abstract修饰;
    没有方法体
    具体实现是通过子类提供的具体方法实现的。
  • 抽象类:abstract定义的规范。抽象方法没有确定的。包含抽象方法的就是抽象类

- 抽象类的使用要点

  • 是个规范,但是不一定每个人都可以做到。
  1. 有抽象方法的类只能定义成抽象类;
  2. 抽象类不能实例化,即不能new一个;
  3. 抽象类包含属性、方法、构造方法。但是构造方法不能用来new实例;
  4. 抽象类只能用来被继承;
  5. 抽象方法必须被子类实现

3.接口(interface)

只有抽象方法和常量。

  • 接口 : 契约(本质:还是抽象类)…如果是xxx,则你必须实现…
  • 只有规范,只有方法的类型。自己无法写方法:是专业的约束。
  • 是规范(方法声明)与实现的分离。

- 区别♥

  • 普通类:具体实现
  • 抽象类:具体实现+规范(抽象的方法)
  • 接口:规范

- 接口的作用:

  1. 接口是约束。
  2. 实现类可以实现多个接口,也就是接口可以实现多继承
  3. 定义一些方法,让不同的人实现,接口一样,实现的方式不一样。
  4. 方法:所有的类型都是public abstract类型的类。
  5. 静态 常量(属性): public static final
  6. 调用:直接void(do);
  7. 接口不能实例化,因为接口中不可以构造方法。
  8. 可以实现多个接口:通过implements
  9. 实现接口中的类之后,必须重写接口中的方法。

- 接口的使用

  1. 默认public abstract void xxx();抽象方法;
  2. 默认public static final类型的常量;
  3. 接口可以多继承;
- 接口的默认方法和静态方法
  • 也被称为是扩展方法。
  • default关键字表示默认方法。
  • 所有这个接口的实现的类都会继承这个方法。
  • 从属于接口(一种特殊的类)。
  • 默认方法是静态的。

- 接口的多继承

可以有多个父类:可以继承与多个父类。必须实现所有的方法。


4.instanceof 运算符

用来判断一个对象是什么类型:判断两个关系是否存在父子继承关系。

A instanceof B:
能不能编译通过,取决于A与B之间是否存在继承关系。
三条关系线:
Object>Person>Student
Object>Person>Teacher
Object>String

1	Object s1 = new Student();

        System.out.println(s1 instanceof Student);  //true
        System.out.println(s1 instanceof Person);  //true
        System.out.println(s1 instanceof Object);  //true
        System.out.println(s1 instanceof Teacher);  //false
        System.out.println(s1 instanceof String);  //false

所以,s1,与teacher、string不在同一棵树上。

2	Person s2 = new Student();
		
        System.out.println(s2 instanceof Student); //true
        System.out.println(s2 instanceof Teacher);  //false
        System.out.println(s2 instanceof Object);   //true
      //  System.out.println(s2 instanceof String); 直接编译报错,直接不同路线。
        System.out.println(s2 instanceof Person);  //true

k

3	 Student s3 = new Student();
 	
         System.out.println(s3 instanceof Student);  //true
      //  System.out.println(s3 instanceof Teacher);	直接编译报错,同级不同路线
        System.out.println(s3 instanceof Object);  //true
       // System.out.println(s3 instanceof String);		直接编译报错,直接不同路线。
        System.out.println(s3 instanceof Person);  //true

- 类型之间的转换(非基本类型)

  1. 强制类型转换(会丢失方法)= = = 高(父)- - - > 低(子)
  2. 向上转型:不用强制转换,添加方法等
  3. 方便方法的调用,减少重复代码。

5.常用类

  1. 包装类
    八大基本类型都有:自动装箱和拆箱。(因为需要面向对象)
  2. 枚举类:
    最基本的用法掌握即可:
定义:   enum 枚举名字{
		枚举体(简单的列表常量)最后一个末尾可以不写分号
	}
遇到复杂的东西时候,直接创建一个其他类即可。

创建枚举类型:

enum Season{
    SPRING,SUMMER,AUTUMN,WINTER
}
System.out.println(Season.SUMMER);

遍历输出:

for(Season k : Season.values()){
            System.out.print(k+"\t");
        }

switch与枚举:

int a = new Random().nextInt(4);//生成0,1,2,3四个随机数。
        switch(Season.values()[a]){
            case SPRING:
                System.out.println("春天");
                break;
            case SUMMER:
                System.out.println("夏天");
                break;
            case AUTUMN:
                System.out.println("秋天");
                break;
            case  WINTER:
                System.out.println("冬天");
                break;
        }

九、异常:Exception

  • Process finished with exit code 1 后面是1,表示存在异常;后面是0表示正常退出。
  • 出现异常的时候,程序可以安全退出, 处理完之后继续执行。
    用户输入的问题、不存在的问题、内存不够的问题…
  1. 被除数为0:ArithmeticException:运算条件异常
  2. 检查型异常:用户错误或问题引起的异常,程序员无法预见的。
  3. 运行时异常:写的时候不报错,运行时可以在编译时忽略。
  4. 错误:非异常。栈溢出等。如无限循环:StackOverflowError

异常的分类:

Throwable类、Exception、Error(jvm出错,重启。。)

Exception:

  • RuntimeException(UncheckedException)运行时异常,编译器不知道,编译的时候不会报错;
  • CheckedException:编译时的异常,编译时候就通过不了

异常类结构层次图:

java面向对象的代码 java面向对象基础知识_java

异常的处理

1.抛出+捕获异常:

处理异常的五个关键字:try、catch、finally、throw、throws
快捷键:自动包裹代码捕获异常:选中当前代码+Ctrl+Alt+T:try/catch/finally

  1. 分成三块:try+catch+finally。可以使用多个catch: 但是假设要捕获多个异常,异常必须从小到大捕获。Throwable、其次Exception,最小error,最先写error。
try{					
          //想要捕获的异常类型
            System.out.println(a/b);//语句1
            System.out.println(c/d);//语句2
             
        }catch (Error e){				
        //catch 捕获异常(先小后大)
            System.out.println("Error");
        }catch (Exception e){
            System.out.println("Exception");
        }catch (Throwable e){
            System.out.println("Throwable");
        } 
        finally {           
        //善后工作(不管有无处理异常,都正常输出)
            System.out.println("finally");
        }
        //finally 可以不要,用于:假设IO资源关闭,就会用到。try、catch 一定要。操作系统的资源也得关闭。
注意: 1.catch后面的语句如果是由父子关系的时候,先写子类,后写父类。没有父子关系可以不管先后。
 		2.语句1出现的异常,往后解决之后,不会再返回语句2.

2.声明异常

  • 谁调我谁处理。(推迟处理 )
  1. Throw:手动抛出异常,在方法中使用
public void test(int a,int b){
        if (b==0){
            throw new ArithmeticException();     //主动抛出异常,方法中使用
        }
  1. Throws:假设这方法中,处理报不了这个异常。方法上抛出异常
public static void main(String[] args) {
        try {					//用了try、catch捕获异常之后,程序继续往下执行,如有异常,直接此处结束
            new Test().test(1,0 );		//匿名内部类
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //假设这方法中,处理报不了这个异常。就在方法上抛出异常
    public void test (int a,int b) throws ArithmeticException{					//方法上抛出异常
        if (b==0){
            throw new ArithmeticException();			
            	//方法中主动抛出异常
        }
    }
  1. ♥ throw 和 throws的区别:几乎没有相同的地方。
    throw:生成一个异常对象,并手动抛出,在方法内部;
    throws:自动、在方法声明的末尾处,抛出异常(处理异常的方式)。先存在异常,“上有排污,下游治污”

3.try-with-resource自动关闭

本质上还是try-catch-finally。
自动关闭资源。
try(****);{ } 自动实现了AutoClosable的接口。
可不用finally。jvm跑的还是try-catch-finally。

4.自定义异常:

  1. 进入可能会存在异常的方法
  2. 传递参数a
  3. 判断是否要抛出异常,无则继续输出
  4. 对这个方法的参数进行调用,捕获自定义的MyException异常
  5. 打印异常的消息(自定的MyException异常里的toString();)

(规划一整套异常体系比较难)

处理异常的思路

  1. 细心看异常信息,确定异常种类、相关代码行(独立解决50+);
  2. 确定上下文相关的关键词信息(疑难问题,需要);
  3. 拷贝异常信息百度10篇以上,查看相关帖子,找思路(搜具体名词、再减少关键词放宽条件)(用空格代替标点符号);
  4. 前两步不会再向同级请教;
  5. 前三步无法解决,请教领导。

- 总结:

常见的RuntimeException异常:自己要解决的

  1. ArithmeticException
    逻辑上的不严密造成的,比如除数为0;这种情况下要加以控制语句if何时可行条件,修改。
  2. NullPointerException
    空指针异常:对象(变量在栈中)是空的时候,调用了他的方法(此时堆中是没有的)。
    解决方法:加以判断if(变量!= null);
  3. ClassCastException
    不可以转换的类型:if(a instanceof b){ }来判断一下是不是同一个类型的,是的话可以强制转换,不是就不转了。
  4. ArrayIndexOutOfBoundsException
    数组越界了:范围之外(数组)
    解决方法:加以判断if(a>0&&a<arr.length){ }
  5. NumberFormatException
    数字格式化异常:引入正则表达式判断是否为数字。

CheckedException异常

  1. 创建的时候异常:可以检查出来的。

实际应用中的经验总结

1 . 处理运行异常时,采用逻辑去合理规避同时辅助try-catch处理
2. 在多重catch块后面,可以加上一个catch(Exception)来处理可能会被遗漏的异常。
3. 对于不确定的代码,也可以加上try-catch,处理潜在的异常
4. 尽量去处理异常,切记不要只是简单的调用printStackTrace()去打印输出,在printStackTrace()前面,增加一些处理异常的代码块(把我们的损失降到最低)
5. 具体如何处理异常,要根据不同的业务需求和异常类型去决定
6. 尽量添加finally语句块去释放占用的资源:IO流、Scanner等