java对象篇

一、面向对象编程(OOP)

  • 面向对象和面向过程
  1. 面向过程思想:线性思维

    • 步骤清晰简单,顺序执行

    • 适合处理一些较为简单的问题

  2. 面向对象思想

    • 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独的思考。最后才对某个分类下的细节进行面向过程的思索。

    • 合适处理复杂的问题,适合处理需要多人协作的问题

  3. 对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。

  • 面向对象:
  1. 本质:以类的方式组织代码,以对象形式的组织(封装)数据
  2. 抽象:将一个对象的共同特性抽取出来
  3. 三大特性:
    1. 封装
    2. 继承
    3. 多态
  4. 从认识的角度来考虑是先有对象后有类。对象是具体的事物。类是抽象的,是对对象的抽象。
  5. 从代码运行的角度考虑是先有类后有对象。类是对象的模板。

二、回顾方法的定义和调用

1.方法的定义

  • 修饰符

  • 返回类型

  • break return的区别:

    ​ break语句的使用场合主要是switch语句和循环结构。在循环结构中使用break语句,如果执行了break语句,那么就退出循环,接着执行循环结构下面的第一条语句。如果在多重嵌套循环中使用break语句,当执行break语句的时候,退出的是它所在的循环结构,对外层循环没有任何影响。如果循环结构里有switch语句,并且在switch语句中使用了break语句,当执行switch语句中的break语句时,仅退出switch语句,不会退出外面的循环结构。

    ​ continue语句是这5种结束循环的方式中最特殊的,因为它并没有真的退出循环,而是只结束本次循环体的执行,所以在使用continue的时候要注意这一点。

    ​ 如果在程序中遇到return语句,那么代码就退出该函数的执行,返回到函数的调用处,如果是main()函数,那么结束整个程序的运行。

  • 方法名

  • 参数列表

  • 异常抛出

2.方法的调用

  • 静态方法:static,通过类名可直接调用
  • 非静态方法:需要实例化后调用

非静态方法可以调用静态方法和非静态方法

public void Method1(){
    Method2();
    Method3();
}
public static void Method2(){}
public void Method3(){}

静态方法只能调用静态方法

public static void Method1(){
    Method2();
    //只有实例化后才可以调用非静态方法
    //Method3();报错
}
public static void Method2(){}
public void Method3(){}
  • 形参和实参
  • 值传递和引用传递
//值传递,不会改变原有的数据
public static void main(String[] args) {
    int a=1;
    System.out.println(a);
    Change(a);
    System.out.println(a);
}
public static void Change(int a){
    a=100;
}
//两次输出都是1
//引用传递
public class MethodDemo02 {
    public static void main(String[] args) {
        Person person =new Person();
        System.out.println(person.name);//默认为空,输出null
        person.name="韩小小";
        System.out.println(person.name);//输出韩小小
    }
}
//一个类中只能有一个public
 class Person{
    String name;
}
  • this关键字
  • 递归

三、对象的创建

  1. 类和对象的关系

    1. 类是一种抽象的数据类型,它是对某一类事物整体的描述或定义,但是并不代表一个具体的事物
    2. 对象是抽象概念的具体实例
  2. 创建与初使化对象

    1. 使用new关键字

    2. 使用new关键字的时候,除了分配内存空间外,还会给创建好的对象进行默认初使化以及对类中的构造器的调用

    3. 类中的构造器也称为构造方法,是在进行创建对象的时候必须调用的,并且构造器有以下两个特点

      1. 必须和类的名字相同
      2. 必须没有返回值,也不能写void
      alt+ins快捷插入构造方法
      构造方法的作用是
      1.当用new初使化对象时会调用
      2.可以用来初使化类中的字段
      构造方法如果显式的定义了,则默认就不生成不带参数的构造方法
      

四、创建对象内存分析


当程序运行时,会首先在堆中的方法区内加载类的信息,如方法、常量(放在常量池中),同时将在静态方法区中加载静态方法和静态变量;然后会将main方法的引用压入到栈的最底层,当对象创建时,将对象的引用依次压入栈中,栈中的引用指向椎中的内存,对象成员赋值时,读取方法区的信息进行赋值;可直接调用静态方法区的方法

五、封装

  • 该露的露,该藏的藏
    • 程序设计追求“高内聚,低耦合”。
      • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉
      • 低耦合:仅暴露少量的方法给外部使用,就是说两个相关的模块尽可以能把依赖的部分降低到最小,不要让两个系统产生强依赖
  • 封装(数据的隐藏)
    • 通常,应禁止直接访问一个对象中数据的实际表示,而应该操作接口来访问,这称为信息隐藏
  • 记住:属性私有,get/set
  • 封装的好处
    • 提高程序的安全性,保护数据
    • 隐藏代码的实现细节
    • 统一接口
    • 系统可维护性增强

六、继承

  • 继承的本质是对某一批类的抽象,从而现实对现实世界更好的建模
  • 用extends关键字,意思是“扩展”,子类是父类的扩展
  • java只有单继承
  • 继承是类和类之间的一种关系,除此之外,类与类之间还有依赖、组合、聚合等关系
  • 继承是一种is a的关系

七、super和this

super:

  • 代指父类对象,可通过super.来调用父类中的成员
  • 当new一个子类对象时,默认会去调用父类的构造方法,其写法上省略了一个super();
  • super()在构造函数中是调用父类的构造器,必须要匹配起来,若重写了带参数的构造器,则默认的不带参数的构造器会被删除
  • super或this调用构造方法必须放在构造方法的第一行

this:

  • 代指当前类的对象,可通过this.来调用当前对象的成员
//父类
public class Person {
    public Person(int age) {
        this.age = age;
    }

     int age=50;//修饰符为默认的,不用写
     public void Test1(){
         System.out.println("this is father calss");
     }
}
public class Teacher extends Person{
    public Teacher() {
        super(5);//调用父类的构造器,并传给父类参数
        this.age=10;
    }
    public int age=10;
    public void Test(int age){
     	System.out.println(this.age);//输出10,当前对象的age
        System.out.println(age);//输出5,传递过来的参数,若没有传参,则为当前对象
        System.out.println(super.age);//输出0,父类的age,但如果父类成员的修饰符为private,则无法调用
        Test1();//输出子类的Test1方法
        this.Test1();//输出子类的Test1方法
        super.Test1();//输出父类的Test1方法
    }
}
public class Application
{
    public static void main(String[] args) {
        Teacher teacher=new Teacher();
        teacher.Test(5);
    }
}

八、方法重写

  • 重写是针对类的方法的,若父类方法和子类方法全是static修饰,则对象调用的方法和声明的对象类型有关,static方法和重写没什么关系,因为在类加载时static方法就已经被加载到静态方法区了
public class A {
    public static void Test(){
        System.out.println("A-->Test");
    }
}
public class B extends A{
    public static void Test(){
        System.out.println("B-->Test");
    }
}
public static void main(String[] args) {
      A b = new B();
      b.Test();//调用A类的方法
      B b1 = new B();
      b1.Test();//调用B类的方法
}
  • 若存在继承关系,子类会重写父类的方法,如下,在new对象时,将父类的引用指向了子类,可以用上面的原理图来理解,子类重写了父类的方法,因此调用父类的方法,就是调用子类重写后的方法

  • 修饰符的范围:子类的范围可以扩大,但不可以缩小,就是说不能比父类的访问级别低 ,默认的修饰符是空,含义是指在同一个包下的
  • 异常的抛出可以被缩小,不能被放大
  • 当父类的功能子类不需要或不能满足子类时,可进行方法的重写

九、多态(父类引用指向子类对象)

  • 动态编译:类型:可扩展性 ,只有在程序运行的后才能确定对象的类型

  • 即同一方法可以根据发送对象的不同而采用多种不同的行为方式

  • 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多

  • 多态存在的条件

    • 有继承关系
    • 子类重写父类的方法
    • 父类引用指向子类对象Father f1=new Son();
  • 有三种方法不能重写

    • static静态方法,属于类,不属于实例
    • final:常量,存在于常量池中
    • private方法
  • 注意:多态是方法的多态,属性是没有多态性的

0

public class Person {
    public  void Run(){
        System.out.println("Person run");
    }
}
public class Student extends Person{
    @Override
    public void Run() {
        System.out.println("Student run");
    }
    public void Eat(){
        System.out.println("Student eat");
    }
}
public static void main(String[] args) {
    //一个对象的实际类型是确定的
    // new Student()
    // new Person()

    //可以指向的引用是不确定的,父类可以指向子类的引用
    Student s1 = new Student();//Student能调用的对象都是自己的或继承父类的
    Person s2 = new Student();//Person类指向子类,但不能调用子类独有的方法
    Object s3=new Student();
    //如果不重写子类的方法,则调用Run全都会调用父类的方法,因为子类继承了父类的方法
    //如果子类重写了父类的方法,则调用Run都会输出子类重写后的方法,子类已经重写了父类的方法
    s1.Run();
    s2.Run();
    //对于子类中父类没有方法,父类对象无权调用,除非使用强制类型转换
    s1.Eat();
    ((Student)s2).Eat();
}
  • 总结:
    • 所谓多态就是子类重写了父类的方法,当把父类对象指向子类时,父类对象会表现出子类对象的特征,也就是调用子类重写后的方法,从而实现一个同一方法表现出不同的行为(父类对象直接调用父类本身的方法,以及父类对象指向子类对象调用子类重写后的方法)。
    • 父类对象不能调用子类独有的方法
    • 要实现多态必须要有继承关系

十、instanceof和类型转换

instanceof:
  • instanceof的作用是判断一个对象是什么类型,以及子类和其他类是否存在父子关系,存在返回true,否则为false

  • System.out.println(X instanceof Y);能否通过编译,取决于X和Y类型有没有父子关系

  • System.out.println(X instanceof Y);是否为true,则取决于X所指向的实际类型是不是Y类型或者其子类型

  • 简单来说intanceof是用来判断一个对象是不是一种类型或者其子类型,是返回true,否则为false

  • instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为:

    boolean result = obj instanceof Class
    

      其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。

      注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。

            Object obj=new Student();
            System.out.println(obj instanceof Student);
            System.out.println(obj instanceof Person);
            System.out.println(obj instanceof Object);//子类的实例化需要先调用父类的构造方法,父类是包含于子类的,因此在判断时,返回true
            System.out.println(obj instanceof Teacher);
            System.out.println(obj instanceof String);
            System.out.println("++++++++++++++++++++++++++");
            Person Per=new Student();
            System.out.println(Per instanceof Student);
            System.out.println(Per instanceof Person);
            System.out.println(Per instanceof Object);//子类的实例化需要先调用父类的构造方法,父类是包含于子类的
            System.out.println(Per instanceof Teacher);
            //System.out.println(Per instanceof String);//编译不通过
            System.out.println("++++++++++++++++++++++++++");
            Student stu=new Student();
            System.out.println(stu instanceof Student);
            System.out.println(stu instanceof Person);
            System.out.println(stu instanceof Object);//子类的实例化需要先调用父类的构造方法,父类是包含于子类的
            //system.out.println(stu instanceof Teacher);//编译不通过
            //System.out.println(Per instanceof String);//编译不通过
            
            //student\person\object类均输出true,其他为false
    
引用类型类型转换:
  • 子类转父类可以直接进行转换,可能丢失方法,子类的独有方法不能被父类调用
  • 父类转子类需要进行强制转换
  • 优点:方便方法的调用,减少代码重复,使代码更简洁
            //Student类是Person类的子类,Eat方法为Student类独有

			//父类引用指向子类对象
            //子类转父类可以直接转,但会损耗一些方法(子类的方法父类无法调用)
            //父类转子类,需要强制类型转换
            Student stu=new Student();
            stu.Eat();
            Person stu1 = stu;
            //stu1.Eat();无法调用
            ((Student)stu1).Eat();

十一、静态static

static

对象可以调用静态属性,也可以通过类名调用,推荐使用类名调用,静态属性被类中的实例所共享。

静态方法不能调用动态方法,因为静态方法在类加载的时候加载的,而动态方法是在创建对象的时候加载的。

public class Student {
    private static int age;//静态属性
    private int score;//非静态属性
    public void run(){
        Student.go();
        go();
    }
    public static void go(){
        //run(),静态方法不能调用动态方法,因为动态方法是属于对象的,只有在对象创建后并通过对象来调用
    }
    public static void main(String[] args) {
        Student st1=new Student();
        System.out.println(st1.age);
        System.out.println(st1.score);
        System.out.println(Student.age);//推荐,静态成员能被类中的实例所共享
        go();
        Student.go();
        new Student().run();
    }
}
代码块和静态代码块
  • 在创建对象时,执行构造方法之前还会执行匿名代码块以及静态代码块,静态代码块在程序中只能执行一次

  • 执行顺序 :静态代码块->匿名代码块->构造方法

public class Person {
    static {
        //代码块
        System.out.println("静态代码块");//Java静态代码块中的代码会在类加载JVM时运行,且只被执行一次
    }
    {
        //代码块
        System.out.println("匿名代码块");
    }
    public Person() {
        System.out.println("构造方法");

    }
    public static void main(String[] args) {
        new Person();//静态代码块先执行,然后是匿名代码块,最后是构造方法
        System.out.println("=========================");
        new Person();//静态代码块只执行一次,这里只输出匿名代码块和构造方法
    }
}
静态导入包

静态导入包,可直接调用包中的静态方法

//静态导入包,可直接调用包中的静态方法
import static java.lang.Math.random;
import java.lang.Math;
public class Test {
    public static void main(String[] args) {
        System.out.println(Math.random());
        System.out.println(random());
    }
}

十二、抽象类

  • 抽象类要用abstract来实现
  • 抽象类中的抽象方法要加abstract
  • 不能创建抽象类的对象,只能用子类来实现
  • 单继承
  • 抽象类就是一种约束
  • 抽象类中也有构造方法

十三、接口

  • 对比:
    • 普通类:只有具体实现
    • 抽象类:具体实现和规范(抽象方法)都有
    • 接口:只有规范
  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是...则必须能...”的思想。
  • 接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
  • OO的精髓,是对对象的抽象,接口最能体现这一点。
  • 我们讨论设计模式都只针对具备了抽象能力的语言,就是因为设计模式所研究的,实际上就是如何合理的去抽象。
  • 声明接口的关键字是interface
  • 接口没有构造方法
  • 接口中可以有属性,为常量,默认属性省略public static final
  • 接口中方法默认为public abstract修饰,一般省略
public interface InterTest {
    void test();
    int test2();
}

public interface UserService {
    int AGE=99;// 默认属性省略public static final,常量
    public static final int AGE2=98;
    void add();
    public abstract void del();
    void up();
    void query();
}

public class UserDemoImpl implements InterTest, UserService {
    @Override
    public void test() {
    }
    @Override
    public int test2() {
        return 0;
    }
    @Override
    public void add() {
    }
    @Override
    public void del() {
    }
    @Override
    public void up() {
    }
    @Override
    public void query() {

    }
}

十四、内部类

  1. 成员内部类
public class NumInnerClass {
    private int ID=66;
    public void Test(){
        System.out.println("this is outter class method");
    }
    //注意public关键字
    public class InnerClass{
        public void Test(){
            System.out.println("this is inner class Test");
        }
        public void Test1(){
            System.out.println("this is inner class Test1");
        }
        public void Test3(){
            System.out.println(ID);//可调用外部类的private成员
        }
    }
}
public class Application {
    public static void main(String[] args) {
        NumInnerClass numInnerClass=new NumInnerClass();
        numInnerClass.Test();
        NumInnerClass.InnerClass ic = numInnerClass.new InnerClass();//要通过对象.来进行实例化
        ic.Test();
        ic.Test1();
        ic.Test3();
    }
}
  1. 静态内部类(static)
public class NumInnerClass {
    private static int ID=66;
    public void Test(){
        System.out.println("this is outter class method");
    }
    public static class InnerClass{
        public static void Test1(){
            System.out.println("this is inner class Test1");
        }
        public static void Test3(){
            System.out.println(NumInnerClass.ID);//不能调用非静态成员
        }
    }
}

public class Application {
    public static void main(String[] args) {
        NumInnerClass numInnerClass=new NumInnerClass();
        numInnerClass.Test();
        NumInnerClass.InnerClass.Test3();
        NumInnerClass.InnerClass.Test1();
    }
}
  1. 局部内部类
public class Test {
    public void method01(){
        //局部内部类
        class A {
            int age=1;
        }
        A a = new A();
        System.out.println(a.age);
    }
}
public class Application {
    public static void main(String[] args) {
        Test test = new Test();
        test.method01();
    }
}
  1. 匿名内部类
public class Test02 {
    public static void main(String[] args) {
        new Apple().eat();
       	Luzhenguo luzhenguo = new Luzhenguo() {
            @Override
            public void test05() {
            }
        };
    }
}
class Apple{
    public void eat(){}
}
interface  Luzhenguo{
   void test05();
}

十五、异常机制Exception

  • 异常指程序中出现的不期而至的各种状况,如文件找不到、网络连接失败
  • 异常发生在程序运动期间,它影响了正常的程序执行

异常的简单分类

​ 1.检查性异常: 不处理编译不能通过,如打开一个文件不存在

​ 2.非检查性异常:不处理编译可以通过,如果有抛出直接抛到控制台,如空指针

public static void main(String[] args) {
    System.out.println(11/0);//ArithmeticException
}

​ 3.运行时异常: 就是非检查性异常

​ 4.非运行时异常: 就是检查性异常

​ 5.错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略,如栈溢出

public class ExceptionDemo {
    public static void main(String[] args) {
        new ExceptionDemo().a();//Exception in thread "main" java.lang.StackOverflowError
    }
    public void a(){
        b();
    }
    private void b() {
        a();
    }
}

java的异常体系结构

Error

  • Error类对象由java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
  • java虚拟机运行错误(Virtual MachineError),当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时,java虚拟机(JVM)一般会选择线程终止。
  • 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。

Exception

十六、异常处理机制

throw

package Demo06;

public class Test {
    public static void main(String[] args) {
        //ctrl+alt+T
        try {//需要捕获的内容
            int a=11,b=0;
            if (b==0){
                throw new ArithmeticException();//throw关键字可直接抛出异常
            }
            System.out.println(a/b);//此处程序不会走
        } catch (Exception e) {
            //对抛出异常的处理,如果要捕获多个异常,参数顺序应该是从小到大,否则编译直接报错
            System.out.println("111");
        }catch (Error error){
            System.out.println("222");
        }catch(Throwable  throwable){
            System.out.println("333");
        } finally {//善后工作,始终会被执行,一般用于资源的释放
            System.out.println("f");
        }
    }
}

throws:

throw是抛出异常,throws是往上抛异常

package Demo06;

public class Test {
    public static void main(String[] args) {
        //ctrl+alt+T
		//在Main方法中进行捕获并处理
        try {
            new Test().test(11,0);
        } catch (ArithmeticException e) {
            System.out.println("111");
        } finally {
        }

    }
    //异常如果处理不了,可以抛给下一个调用者
    public void test (int a,int b) throws ArithmeticException{
        if (b==0){
            throw new ArithmeticException();//throw关键字可直接抛出异常
        }
        System.out.println(a/b);//此处程序不会走
    }
}

自定义异常

public class MyException extends Exception{
    //判断是否大于10
    private int a;//定义一个int类型的数用来保存传入的值
    public MyException(int  a) {//构造方法给a赋值
        this.a=a;
    }
	//重写tostring
    @Override
    public String toString() {
        return "MyException{" +
                "a=" + a +
                '}';
    }
}

public class Application {
    public static void main(String[] args) {
        try {
            test(11);
        } catch (MyException e) {
            System.out.println("大于11"+e);
        }
    }
    //可抛出也可直接捕获
    static void test(int a) throws MyException {
        if (a>10){
            throw new MyException(a);
        }
            System.out.println("ok");

    }
}
posted @ 2021-11-18 20:54  是韩信啊  阅读(114)  评论(0编辑  收藏  举报