zoukankan      html  css  js  c++  java
  • 07、面向对象—重要知识点


    前言

          去年四月份大一下半学期正式开始学习Java,一路从java基础、数据库、jdbc、javaweb、ssm以及Springboot,其中也学习了一段时间数据结构。

          在javaweb期间做了图书商城项目、ssm阶段做了权限管理项目,springboot学了之后手痒去b站看视频做了个个人博客项目(已部署到服务器,正在备案中)。期间也不断进行做笔记,总结,但是越学到后面越感觉有点虚,觉得自己基础还有欠缺。

          之后一段时间我会重新回顾java基础、学习一些设计模式,学习多线程并发之类,以及接触一些jvm的相关知识,越学到后面越会感觉到基础的重要性,之后也会以博客形式输出学习的内容。

          现在整理的java知识基础点是在之前学习尚硅谷java课程的笔记基础之上加工汇总,部分图片会引用尚硅谷或网络上搜集或自己画,在重新回顾的过程中也在不断进行查漏补缺,尽可能将之前困惑的点都解决,让自己更上一层楼吧。

          博客目录索引博客目录索引(持续更新)



    一、main方法介绍

    main():作为程序的入口,是一个普通的静态public方法,虚拟机中执行会去找main()方法,若不存在就会报错,存在即执行。

    main方法能与控制台进行交互。

    public class Main{
        public static void main(String[] args){
    	}
    }
    

    其中的args参数我们也可以进行赋值并输出:

    ①命令行中赋值并输出

    首先编译成字节码文件,接着输入java Main "参数1" 1 2 3 后面空格分隔的参数值会赋予到args中,就可以对其进行操作了!!

    ②IDEA中设置参数

    左上角选择你当前运行的java源代码名称—Edit Configuration

    在Program argumnets中设置参数即可

    image-20210127152021434



    二、static关键字

    static:共享的,可以修饰属性、方法、代码块、内部类(无构造器)。

    • 修饰属性:此属性就是类中的静态属性,创建多个对象都有一份共享的属性,一个对象修改的话,其他对象拥有的属性也会更改。
      • 静态变量会随着类的加载而加载,放置在缓存区(方法区的静态域),可以通过类.静态变量直接调用,而不用先创建实例再获取。
      • 类的加载早于对象的加载,加载时间发生在如实例化对象、类名调用静态变量的几个情况下。由于类的加载只有一次,静态变量在内存中只会存在一份。
    • 修饰方法:也就是静态方法,随着类的加载而加载,通过类.静态方法调用。
    • 一般常量也使用static修饰。

    注意点:静态方法中,不能使用this,super关键字,并且静态方法中不能调用非静态的属性及方法。(因为静态方法是随着类加载而加载,实例化对象则是在运行阶段)。

    相关设计模式:单例模式



    三、类成员—代码块

    类的成员:方法、属性、构造器、内部类、代码块

    代码块:也称为Block、初始化块,分别非静态代码块与静态代码块。

    语法

    class Person{
        //非静态代码块
        {
        
    	}
        
        //静态代码块
        static{
            
        }
    }
    
    • 非静态代码块:可在创建属性时,对属性进行初始化
      • 创建实例时执行,每创建一次就会执行一次。
      • 若是有多个代码块,按照顺序执行。
      • 可包裹静态、非静态的属性及方法。
    • 静态代码块:为静态属性赋值
      • 随着类的加载而执行,只执行一次
      • 若是有多个静态代码块,根据顺序执行(可合在一个静态代码块中)
      • 只能包裹静态属性与方法

    使用场景:连接数据库时,加载properties配置文件。



    四、final关键字

    final:表示常量,最终的意思

    final可修饰结构:类、方法、类变量、局部变量

    • 修饰类:此类不能被其他类所继承。
    • 修饰方法:此方法不能被重写。
    • 修饰变量:此变量为常量,可初始化位置有直接初始化、代码块中初始化、构造器中初始化(只能有一处)。
    • 修饰局部变量
      • 形参:表示常量,在方法中不可对其重新赋值(调用方法时会传参)。
      • 方法中参数:表示常量,不可二次赋值。

    初始化举例:下面演示的是不同变量,同一个变量赋过值后无法再重新赋值

    class Person{
        public final double MONEY = 20; //1.直接赋值
        public final int NAME;  
        public final String MAJOR;
        public Person(){
            NAME = 10;  //2.在构造器中赋值
        }
        {
            MAJOR = "数学";   //3.在代码块中赋值
        }
    }
    

    final使用于方法实例:Object的getClass方法public final native Class<?> getClass();

    final使用于类实例:常用类Stringpublic final class String

    final使用于变量:String类中的参数private final char value[];



    五、abstract关键字

    介绍abstract

    abstract:可修饰类与方法

    修饰类:抽象类,一般来说在开发中会提供抽象类子类,让子类进行实现

    • 无法进行实例化
    • 一定有构造器,方便子类对象实例化时候调用

    修饰方法:抽象方法

    • 有抽象方法的必定是抽象类
    • 抽象方法只有方法的声明,没有方法体,例如public abstract void walk();
    • 若子类继承了抽象类,必须重写父类所有抽象方法,否则该子类依旧是抽象类

    注意点:①abstract不能修饰属性,构造器等结构。②不能修饰private属性,静态方法,final方法



    抽象类

    抽象类:主要是用来模型化那些父类无法确定全部实现,而由其子类提供具体实现对象的类。

    下面就是一个简单的子类继承抽象类实现抽象方法:目的是要是实现抽象类调用其walk方法

    abstract class Person{
        public abstract void walk();
    }
    
    class Student extends Person{
        @Override
        public void walk() {
            System.out.println("student走路中.....");
        }
    }
    
    public class Main {
        public static void main(String[] args){
            Person student = new Student();
            Person.walk();//student走路中.....
        }
    
    }
    


    匿名抽象类

    匿名抽象类:对于抽象类我们是无法直接实例化的,但我们可以通过匿名抽象类的方式来进行实例化,需要注意的是这个实例化对象并非是该抽象类,可以看成其匿名子类,实现抽象方法即可使用。

    好处:当我们需要使用某个抽象类中的方法时,一般来说要重新定义一个类来继承抽象类并实现方法,之后将该子类实例化使用实现方法,这里可以直接创建一个匿名子类对象,直接重写方法用。

    使用的例子还是上面抽象类里的例子:

    abstract class Person{
        public abstract void walk();
    }
    
    public class Main {
        public static void main(String[] args){
            //多态:创建匿名抽象类并实例化
            Person person = new Person() {
                @Override
                public void walk() {
                    System.out.println("student走路中.....");
                }
            };
            person.walk();//student走路中.....
        }
    
    }
    

    这里使用多态来进行方法调用。



    应用场景

    需求描述及不合理方案

    image-20210128112839103

    描述:上面几个动物原本是根据不同的科类划分继承的,现在需要给几个动物如cat、dog这几个动物家养的几个小动能,如何设计最合理?

    这里有几个不太合理方案:当做示例

    • 方案一:直接将宠物方法加在Animal类中。
      • 优点:其下所有动物类都可以马上继承其方法,其他新增加的动物也会取得同样行为。
      • 缺点:让原本不是宠物的动物赋予了其方法,很不合理!
    • 方案二:与方案一相同,加Animal类中,不过这里添加的是抽象方法。
      • 优点:其他所有动物类都会重写该方法,定义合理的动作。
      • 缺点:注意其他动物例如老虎狮子,根本完全没必要有并且重写其方法。
    • 方案三:直接把放方法写入到指定的动物身上。
      • 优点:避免其他动物有其宠物的行为。
      • 缺点:对于相同的行为方法,不一样的家宠动物会出现例如doFriendly()、beFriendly()方法,调用时可能会出现不同方法调用。

    理清需求以及合理方案

    需求描述总结

    • 一种可以让宠物行为只应用到宠物身上方法
    • 确保所有的宠物的类都有相同的方法定义的方法。
    • 可以应用到多态

    合理方案:在cat、dog之上创建一个抽象类名为Pet,并且创建带有宠物的方法,这样指定动物就能够继承其方法,并且还能够使用多态,通过Pet类来进行声明接收。

    相关关系见下图,真的秒呀:

    image-20210128114317574



    六、Interface接口

    1、介绍Interface

    定义成员,通过implements来实现接口

    Interface:接口仅仅只是有相同的行为特征,继承是"是不是"的关系,接口是"能不能"的关系,也支持多态,可以取代具体的子类或抽象父类作为参数或返回类型,那么就可以传入任何实现该接口的东西。

    接口定义成员

    • JDK7之前:只能定义全局常量(public static final)与抽象方法(public abstract),并且这些前缀可不写效果依旧。

      • interface Skill{
            int flyTime = 100;//默认与右边相同:public static final int flyTime = 100;
            void fly();//默认与右边相同:public abstract void fly();
        }
        
    • JDK8:除了全局常量和抽象方法,还可以定义静态、默认方法(技术角度来看是合法的,看起来违背了接口理念)

      • 静态方法(static):可通过接口.静态方法直接调用方法,并执行方法体。

      • 默认方法(default):可通过创建实现类(先实现接口)对象,调用接口的默认方法,执行方法体。

        //接口
        interface Skill{
        	//静态方法
            static void walk(){
                System.out.println("走路....");
            }
        	//默认方法:包含实现体
            default void fly() {
                System.out.println("fly......");
            }
        }
        //实现接口
        class Person implements Skill{
        
        }
        
        public class Main {
            public static void main(String[] args){
            	//直接接口调用
                Skill.walk();//走路....
                //实现类调用默认方法
                new Person().fly();//fly......
        
            }
        
        }
        

    注意:接口没有构造器!!!

    相关设计模式:代理模式、工厂模式



    2、接口特性

    实现多接口

    格式class 类名称 extends 类 implements 接口1,接口2{}

    特点:弥补了Java单继承的局限性。

    接口冲突案例:实现多个接口时都有同名同参数方法需要重写其方法

    interface Skill{
        //默认方法
        default void fly() {
            System.out.println("skill接口的fly......");
        }
    }
    
    interface Clothes{
        //默认方法
        default void fly() {
            System.out.println("clothes会飞......");
        }
    }
    
    //实现两个接口
    class Student implements Skill,Clothes {
        //重写方法
        @Override
        public void fly() {
            System.out.println("student自己会飞");
        }
    }
    
    public class Main {
        public static void main(String[] args){
            new Student().fly();//student自己会飞
        }
    
    }
    

    说明:实现多个接口时,若是都有同名同参数,会出现接口冲突,需要对冲突方法进行重写,否则会报错!!



    接口多继承

    多继承:接口与接口之间是可以继承的,并且能够多继承!

    interface AA{
        void sleep();
    }
    
    interface BB{
        void walk();
    }
    
    //这里使用到了extends继承
    interface CC extends AA,BB{
        
    }
    

    注意:如果类实现多继承的接口,那么必须实现所有的抽象方法,才能进行实例化;没有实现抽象方法的则会变为抽象类。



    匿名接口类

    接口类的实现方式:就是创建一个类实现其接口。

    匿名接口类:与匿名抽象类有点类似,如下

    interface USB{
        void start();
    
        void stop();
    }
    
    //Flash驱动
    class Flash implements USB{
    
        @Override
        public void start() {
            System.out.println("Flash开始准备工作.....");
        }
    
        @Override
        public void stop() {
            System.out.println("Flash结束传输工作.....");
        }
    }
    
    public class Main {
        public static void main(String[] args){
            //接口类实例化
            USB usb = new Flash();
            
            //匿名接口类 (可作为参数传递到方法中,实现多态)
            new USB() { //也可用USB u = new USB(){实现} 多态形式接收
                @Override
                public void start() {
                    System.out.println("xxx驱动启动了.....");
                }
    
                @Override
                public void stop() {
                    System.out.println("xxx驱动结束运行了.....");
                }
            };
        }
    }
    


    接口注意点(3点)

    下面的接口与类是接下来注意点中的使用部分:

    interface Skill{
        //默认方法
        default void fly() {
            System.out.println("skill接口的fly......");
        }
    }
    
    class Person{
        //与接口同名同参数方法
        public void fly(){
            System.out.println("Person的fly...");
        }
    }
    

    注意点如下

    1. 实现接口,若是其接口有默认方法可以进行重写

    2. 若是继承父类以及实现的接口中都有同名同参数的方法时,子类再没有重写情况下,会调用父类中的方法

      • //继承Person以及实现Skill接口   extends写在前
        class Student extends Person implements Skill{
        }
        
        public class Main {
            public static void main(String[] args){
                //调用的是父类的方法
                new Student().fly();//fly......
            }
        
        }
        
    3. 对于父类、接口以及自己重写的方法该如何去调用同名同参数的方法?三种

      • //继承Person以及实现Skill接口   extends写在前
        class Student extends Person implements Skill{
            
            @Override
            public void fly() {
                System.out.println("Student自己会飞啦");
            }
        
            //测试调用不同的fly方法
            public void executeMethod(){
                fly();//调用自己重写的fly()方法
                super.fly();//调用父类的fly()方法
                Skill.super.fly();//调用实现接口的fly()方法,若是有其他接口也如这样调用
            }
        }
        
        public class Main {
            public static void main(String[] args){
                new Student().executeMethod();
            }
        }
        
    4. 针对于父类、接口的属性获取方式:

      • class A{
            public int m = 5;
        }
        
        interface B{
            int m=6;
        }
        
        class C extends A implements B{
            public C(){
                System.out.println(super.m);//直接super.属性,与上面获取父类方法一致
                System.out.println(B.m);//直接B.属性,因为接口中属性是static
            }
        }
        
        
        public class Main {
            public static void main(String[] args){
                new C();
            }
        }
        


    3、接口实例演示

    接口与多态应用

    接口与我们生活中的USB接口也有类似的地方,会定义一些传输数据,以及例如传输数据、开始与结束的方法。

    使用:满足多态,实际上定义了一种规范,在开发中很多都面向接口编程。

    实例:接口的一种使用方式

    //定义了USB的两个规范方法
    interface USB{
        void start();
    
        void stop();
    }
    
    //Flash驱动
    class Flash implements USB{
    
        @Override
        public void start() {
            System.out.println("Flash开始准备工作.....");
        }
    
        @Override
        public void stop() {
            System.out.println("Flash结束传输工作.....");
        }
    }
    
    //打印机驱动
    class Printer implements USB{
    
        @Override
        public void start() {
            System.out.println("Printer开始准备工作.....");
        }
    
        @Override
        public void stop() {
            System.out.println("Printer结束传输工作.....");
        }
    }
    
    //电脑主机
    class Computer{
    
        /**
         * 用于主机进行装配驱动并传输数据
         * @param usb 多态,传入不同驱动
         */
        public void transferData(USB usb){
            usb.start();
            System.out.println("传输数据.....");
            usb.stop();
        }
    }
    
    
    public class Main {
        public static void main(String[] args){
            new Computer().transferData(new Flash());
            System.out.println("更换设备....");
            new Computer().transferData(new Printer());
        }
    }
    
    • USB接口:相当于一种规范,让不同的驱动实现其中的固定步骤。
    • Flash、Printer实现类:用于实现USB接口的方法,两个驱动都有其不一样的启动与结束
    • Computer类:单独电脑类,其中传输方法中的参数就是需要指定驱动类传入,这样的话我想用哪个驱动传入进来即可

    image-20210127193943342

    包含了多态的使用!



    4、接口面试题

    题1:一个类、一个接口,类与接口中有相同属性名,如何调用获取

    interface A{
        int x=0;
    }
    
    class B{
        int x=1;
    }
    
    public class C extends B implements A{
        public void pX(){
            System.out.println(super.x);
            System.out.println(A.x);
        }
        public static void main(String[] args) {
            new C().pX(); 
        }
        
    }
    

    对于继承父类:super.属性

    对于实现接口属性:接口名.属性 因为属性默认为public static final静态常量,所以可直接接口名获取



    七、内部类

    1、介绍内部类及分类

    内部类:java中允许将一个B类声明放入到A类中,那么B就是内部类,A就是外部类。

    • //类,也称外部类
      class A{
      	
        	//内部类
          class B{
              
          }
      }
      

    分类

    • 成员内部类:静态、非静态
    • 局部内部类:方法内,代码块内,构造器内

    分类举例如下

    class Person{
        //1.1静态成员内部类
        static class A{
            
        }
        //1.2非静态成员内部类
        class B{
            
        }
        
        public void method(){
            //2.1 局部内部类(局部方法中)
            class C{
                
            }
        }
        {
            //2.2 局部内部类(代码块中)
            class D{
                
            }
        }
        
        public Person(){
            //2.3 局部内部类(构造器中)
            class E{
                
            }
        }
    }
    


    2、内部类属性方法调用

    成员内部类:一方面作为外部类的成员,另一方面作为一个类

    • 作为外部类成员:可调用外部类的接口;可static修饰;可使用四种权限符
    • 作为一个类:可定义属性、方法、构造器等,可被final修饰,可被abstract修饰

    ①针对于static内部类:其内部方法中无法调用外部类的属性及方法,因为想要调用首先外部类必须是静态的,但是作为外部类是不能被static修饰的。

    ②针对于非static内部类:其内部方法可以调用外部属性与方法。

    • 外部类属性与方法(static):外部类名.属性外部类名.方法
    • 外部类属性与方法(非static):外部类名.this.属性外部类名.this.方法名

    示例演示

    ②中的调用外部类属于与方法(static):正常通过类名调用即可

    class Person{
    
        private static String name;
    
        public static void eat(){
            System.out.println("eat吃东西");
        }
    
        //内部类(非静态)
        class P{
            private String name;
    
            public void eat(){
                //调用外部类静态属性
                Person.name = "123";
                //调用外部类静态方法
                Person.eat();
            }
        }
    }
    

    ②中的调用外部类属于与方法(非static):需要类名+this,与之前实现接口调用属性有点类似

    class Person{
    
        private String name;
    
        public void eat(){
            System.out.println("eat吃东西");
        }
    
        //内部类(非静态)
        class P{
            private String name;
            
            public void eat(){
                //调用外部类属性(非静态)
                Person.this.name = "123";
                //调用外部类方法(非静态)
                Person.this.eat();
            }
        }
    }
    


    3、三个主要问题

    实例化内部类

    内部类也分为两种:静态与非静态

    class Person{
    	//静态内部类
        static class A{
            public void show(){
                System.out.println("我是A的show()");
            }
        }
    
        //内部类
        class B{
            public void show(){
                System.out.println("我是B的show()");
            }
        }
    }
    

    根据上面的代码我们准备好了静态内部类以及内部类:

    • 静态内部类实例:Person.A a = new Person.A(); 直接创建静态内部类实例

    • 内部类实例:

      • //首先实例化外部类
        Person person = new Person();
        //接着再实例化内部类,很合理
        Person.B b = person.new B();
        


    区分内部类与外部类属性

    见代码:之前内部属性调用也有说明

    class Person{
        //①外部类属性
        String name="小明";
        public class Bird{
            //②内部类属性
            String name="麻雀";
            
            //③参数属性
            void show(String name){
                //输出外部类的name
                System.out.println(Person.this.name);  //调用Person类中的this(相当于Bird)的name属性
                //输出成员内部类Bird的name
                System.out.println(name);              //直接name,就是离得最近的形参
                //输出show中的形参name
                System.out.println(this.name);         //this(指的是Person类) 调用这个类的属性
            }
        }
    }
    


    开发中内部类应用(Comparable接口)

    【1】返回局部内部类实现comparable接口的匿名实例

    class MyTest{
    
        //返回一个非匿名接口实现类
        public Comparable<Object> getComparable(){
            //实现Comparable接口
            class MyComparable implements Comparable<Object>{
    
                @Override
                public int compareTo(Object o) {
                    return 0;
                }
            }
            return new MyComparable();
        }
    }
    

    【2】不实现接口实现类,直接返回匿名接口类对象

    class MyTest{
    
        //返回一个匿名接口类
        public Comparable<Object> getComparable(){
            return new Comparable<Object>() {
                @Override
                public int compareTo(Object o) {
                    return 0;
                }
            };
        }
    }
    


    参考资料

    [1]. java类什么时候加载?,加载原理机制是怎么样的?

    [2]. 书籍《head first java 2.0》


    整理者:长路 时间:2021.1.27 23:19

  • 相关阅读:
    ◆ C++中通过溢出覆盖虚函数指针列表执行代码
    关于在OnTimer中连续弹出对话框的讨论
    SetTimer
    Windows内核对象
    日志收缩
    暴力求值
    低级问题
    函数限制
    字符串找字段和表
    android错误提示说明汇总
  • 原文地址:https://www.cnblogs.com/changluya/p/14423027.html
Copyright © 2011-2022 走看看