zoukankan      html  css  js  c++  java
  • 浅显回顾 Java 面向对象的最后方面的知识

    今天主要回顾一下 Java 面向对象的最后一部分的知识,算是对面向对象的一个总结了吧!

    先来讲两个关键字吧!

     
    1. abstract
    如果一个类的所有子类都对这个类中的某个方法做了重写,那么这个时候这个类中的对应方法可以不定义方法体,需要用abstract修饰方法,从而成为一个抽象方法。抽象方法所在的类必须是抽象类
    抽象类不能创建对象。 --- 抽象方法一定是抽象类,但抽象类中不一定有抽象方法。
    抽象类一定不是最终类,因为最终类不能被继承。
    注意:任何一个类都有构造方法
    抽象方法没有方法体,一定要被重写。
    抽象方法可以定义被 static/final/private 修饰吗? --- 不行
    抽象方法中一定不能定义在最终类中。
    如果一个类中的抽象方法用的是默认权限,对子类有什么要求? --- 要求父子类要同包
    package abstractx;
    
    public class AbstractDemo {
        
        //不允许被实例化
        //Pet p = new Pet();
        //p.eat();
        
        //创建的是匿名内部类
        Pet p = new Pet(){
    
            @Override
            public void eat() {
                // TODO Auto-generated method stub
                
            }
            
        };
        
    }
    
    //不想让这个类实例化,就定义一个抽象类
    abstract class Animal{}
    
    //抽象类
    abstract class Pet{
        
        //
        public Pet(){}
        
        //抽象方法,因为长得像方法,但是没有方法体
        public abstract void eat();/*{
            //System.out.println("在吃东西~~~");//有没有方法体都不重要了
        }*/
        
        public void drink(){
            System.out.println("在喝水中~~~");
        }
    }
    
    //子类继承抽象类之后必须重写其中的抽象方法,除非子类也是抽象类
    class Cat extends Pet{
        
        @Override
        public void eat(){
            System.out.println("这只猫在吃土~~~");
        }
        
    }
    
    class Dog extends Pet{
        
        @Override
        public void eat(){
            System.out.println("这只狗在吃猫~~~");
        }
        
    }
     
    练习:定义一个类表示形状,提供获取周长和面积的方法,然后给这个类提供子类:矩形 - 正方形,椭圆 - 圆形
    package abstractx;
    
    public class AbstractExer {
        public static void main(String[] args) {
            Shape f;
            f = new Rectangle(3,4);
            System.out.println(f.getGirth() + "," + f.getArea());
            f = new Oval(4,5); 
            System.out.println(f.getGirth() + "," + f.getArea());
        }
    }
    
    abstract class Shape{
        
        public abstract double getGirth();
        public abstract double getArea();
    }
    
    //代表矩形
    class Rectangle extends Shape{
    
        double width;
        double height;
        
        public Rectangle(double width, double height){
            this.width = width;
            this.height = height;
        }
        @Override
        public double getGirth() {
            return 2 * (width + height);
        }
    
        @Override
        public double getArea() {
            // TODO Auto-generated method stub
            return width * height;
        }
        
    }
    
    //正方形
    class Square extends Rectangle{
    
        private double width;
        public Square(double width) {
            super(width, width);
        }
        
    }
    
    //椭圆形
    class Oval extends Shape{
        
        private double a;
        private double b;
        public static final double PI = 3.14;
        
        public Oval(double a, double b){
            this.a = a;
            this.b = b;
        }
        
        @Override
        public double getGirth() {
            // TODO Auto-generated method stub
            return PI * a * b;
        }
    
        @Override
        public double getArea() {
            // TODO Auto-generated method stub
            return PI * (a + b);
        }
        
    }
    
    //圆形
    class Circle extends Oval{
    
        private double r;
        
        public Circle(double r){
            super(r, r);
        }
    
    }
     
    2. interface
    (作用:作为模板或者是协议、约束等来使用)
    接口中定义的都是抽象方法。类和接口之间用的是 implements 关键字来产生关联 --- 实现。类和实现接口之后需要重写接口中所有的抽象方法
    接口不允许被实例化,也没有构造方法。
    在 Java 中,支持的是类和接口之间的多实现 --- 一个类可以实现多个接口
    在 Java 中,支持接口之间的多继承(接口可以继承接口),
    在 JDK1.8 中,接口中允许定义实体方法 -- 这个是实体方法必须用 default 修饰
    package cn.tedu.interfacex;
    
    import java.io.Serializable;
    
    public class InterfaceDemo {
        
        public static void main(String[] args) {
            
            System.out.println(Shape.girth);
            //Shape.girth = 1;//说明是使用final修饰的
            
            //接口不允许实例化
            //Shape s = new Shape();
        }
    }
    
    interface Shape extends Cloneable,Serializable{
        
        double girth = 0;//默认是用的 static,final
        
        //public Shape(){}不允许使用
        
        //接口中的方法默认public abstract修饰
        /*public abstract */double getGirth();
        public abstract double getArea();
        
    }
    
    //利用implements关键字让类和接口产生了联系 --- 实现
    //Rectangle实现了 Shape接口
    /*class Rectangle implements Shape, Cloneable{
        
    }
    */
    
    interface E{
        void main();
    }
    
    /*class B implements E{
    
        void main() {//报错了,范围不一样
            
        }
        
    }*/

    关于接口的实现中,我们有:

    package cn.tedu.interfacex;
    
    public class InterfaceDemo2 {
        
        public static void main(String[] args) {
            
            A a = new B1();
            
            //在 Java 中支持的是类和类之间的单继承
            //所以此时会形成一颗结构树
            //所以比较容易的就能确定两个类之间是否有继承关系
            //因此在进行强制转换的时候
            //会检查要转换的对象的声明类和转换的类型是否有继承关系
            //a对象的声明类型是 A 类,要转换的类型是B1
            //B1继承了A,所以在编译时期就不报错
            //到了运行的时候才会检查对象的实际类型和要转换的类型是否一致
            //运行的时候,发现a的实际类型是 B1,要转换的类型是B1
            //类型一致,允许转换
    
            B1 b1 = (B1) a;//编译、运行都不会报错
            
            //a对象的声明类型是 A 类,要转换的类型是B2
            //B2继承了A,所以在编译时期就不报错
            //到了运行的时候,a的实际类型是B1,要转换的类型是B2
            //类型不一致,所以报错 --- ClassCastException
    
            /*B2 b2 = (B2) a;//编译通过,但是运行会报错
            B2 b3 = (B2) b1;//编译直接不通过
            C c = (C) a;*///编译直接不通过
            //在 Java 中,类和接口之间是多实现,接口和接口之间是继承关系
            //所以构成了一张图状结构 --- 网状结构,
            //不容易确定两个节点之间的关系
            //因此在编译时期为了提高效率放弃检查
            //直到运行时候在确定类型是否是否相同
            D d = (D) a;//编译通过,但是运行报错
            
        }
    }
    
    class A{}
    
    class B1 extends A{}
    
    class B2 extends A{}
    
    class C{}
    
    interface D{}
     
    接着我们谈谈关于内部类方面的知识吧!!
    内部类
     
       1. 方法内部类
    定义在方法中的类 --- 方法/局部内部类 --- 为了重复使用某段逻辑,并且使这段逻辑只从属于某一个方法使用
    package cn.tedu.innerclass;
    
    public class InnerDemo1 {
    
        public static void main(String[] args) {
            
            Outer1 outer1 = new Outer1();
            outer1.m();
        }
        
    }
    
    class Outer1{
        
        int i = 10;
        
        public void m(){
            System.out.println("Outer~~~");
            
            //当方法内部类使用所在的方法中的数据的时候,
            //要求这个属性的是一个常量
            //从JDK1.8开始,方法内部类使用到当前方法中的数据的时候,将该数据默认为常量,不能改变
            //常量的隐式声明:
            int j = 5;
            
            //方法内部类
            //只能在定义它的方法中使用
            //可以使用外部类中的属性何方法
            //如果内部类和外部类存在同名属性或者方法,则使用内部类中定义
            //只能用abstract/final修饰
            //方法内部类可以定义非静态的属性和非静态方法
            //但是不能定义静态变量和静态方法
            //然而定义静态常量
            class Inner1{//不能用static 修饰
                
                int k = 8;
                static final int x = 7;//会报错,加final变成一个常量
                
                public void m(){
                    System.out.println("Inner~~~");
                    i += 5;
                    m2();
                    //外部类.this.外部类的方法或者属性
                    Outer1.this.m2();
                    
                    System.out.println(j);
                    //j++;//会报错
                    
                }
                
                public void m2(){
                    System.out.println("Inner m2~~~");
                }
                
            }
            
            Inner1 i1 = new Inner1();
            i1.m();
        }
        
        public void m2(){
            System.out.println("m2~~~");
        }
        
    }
        2. 成员内部类
    Outer2.Inner2 oi2 = new Outer2().new Inner2();
     
    package cn.tedu.innerclass;
    
    public class InnerDemo2 {
        
        public static void main(String[] args) {
            
            Outer2 o2 = new Outer2();
            
            Outer2.Inner2 oi2 = new Outer2().new Inner2();//利用外部类对象创建内部类
            System.out.println(oi2.j);
        }
        
    }
    
    class Outer2{
        
        int i = 3;
        
        Inner2 i2 = new Inner2();
        
        //成员内部类
        //可以使用外部类中的属性和方法
        //可以定义非静态属性和非静态方法
        //但是不能定义静态属性和静态方法
        //然而定义静态常量
        class Inner2{//修饰不受什么限制
            
            int j = 10;
            static final int k = 8;//也是要加final
            
            public void m(){
                i += 3;
                Outer2.this.m();//调用外部类中的,不然就是递归了
            }
            
        }
        
        public void m(){
            System.out.println("Outer~~~");
        }
        
    }
        3. 静态内部类
    用 static 修饰的类
    Outer3.Inner3 oi3 = new Outer3.Inner3();
    package cn.tedu.innerclass;
    
    public class InnerDemo3 {
    
        public static void main(String[] args) {
            
            Outer3.Inner3 oi3 = new Outer3.Inner3();
            oi3.m();
            
        }
        
    }
    
    class Outer3{
        
        int i = 0;
        
        //静态内部类
        //只能使用外部类中的静态属性和静态方法
        //静态内部类中可以定义一切的方法和属性,无论静态还是非静态
        static class Inner3{
            
            
            int j = 8;
            static int k = 4;
            
            public void m(){
                //System.out.println(i);//报错
            }
            
        }
        
    }
        4. 匿名内部类
    匿名内部类本质上是实现了对应的接口或者是继承了对应的类
    任何一个接口都可以存内在匿名内部类形式 
    一个类只要可以被继承,那么就可以存在匿名内部类形式 --- 最终类不存在匿名内部类的形式
    package cn.tedu.innerclass;
    
    public class InnerDeom4 {
    
        public static void main(String[] args) {
            
            //匿名内部类
            //a是匿名内部类产生的对象
            //匿名内部类实际上是实现了对应的接口
            A a = new A(){
    
                @Override
                public void m() {
                    System.out.println("running");
                }
                
            };
            
            a.m();
            //匿名内部类实际上是继承了对应的类
            B b = new B(){
    
                @Override
                public void m() {
                    System.out.println("running");
                }};
                b.m();
                
                //C c = new C(){};
        }
        
    }
    
    interface A{
        
        void m();
        
    }
    
    abstract class B{
        
        public abstract void m();
    }
    
    final class C{}
     
    扩展:类中可以定义类,类中也可以定义接口,接口中也可以定义类,接口中也可以定义接口 --- 如果类中定义了接口或者式接口中定义了接口,那么称之为内部接口 --- 类中定义的接口,以及接口中定义的类和接口默认都是静态的。
     
    谈到这儿,还有个 Lambda 表达式的内容:
    package cn.tedu.innerclass;
    
    public class LambdaDemo {
    
        public static void main(String[] args) {
            
            //接口中只定义了1个抽象方法
            //可以利用
            /*Calc c = new Calc(){
    
                @Override
                public double add(double i, double j) {
                    // TODO Auto-generated method stub
                    return i + j;
                }};*/
            //表示重写Calc中的唯一的一个抽象方法add
            //Lambda表达式只能作用在函数式接口上
            //方法体只有一句,可以省略{}和return 不写
            //唯一的依据方法体的计算结果默认为当前方法的返回值
            
            //Calc c = (double i, double j) -> i + j;
            
            //重写的是 Calc 接口中的方法add
            //add方法的参数列表的类型是已知的
            //可以省略参数类型不写
            //函数式编程
            Calc c = (x, y) -> x + y;
            
            System.out.println(c.add(4.3, 2.5));
        }
        
    }
    
    interface Calc{
        
        double add(double i, double j);
    }

    接着,前面打一个小结,接下来进行包的介绍:

    声明包用的是 package --- 区分同名类,进行功能的划分
    导入包用的是 import --- 导包的作用是用于提示代码从哪儿去找这个类(比如,我们前段时间经常使用的 Scanner、Arrays)
    这个类
    * 表示导入当前包下的所有的类但是不包括子包下的类
    java --- 原生包,提供的一些常用的包,sun 公司自己用的
    javax --- 扩展包,后阶段用的比较多
    org --- 第三方厂商提供的一些常用的包,sun公司感觉比较好就收过来了
     
    java.lang - 核心/基本包( System  String)  ,包含了 Java 程序运行需要的基本类,在 Java 程序启动的时候,包下的类就已经自动加载到内存中,所以使用的时候可以不用导包
    java.awt
    java.applet --- JDK 1.9 后大部分类已经被抛弃了
    java.util - 工具包
    java.math --- 数学运算
    java.io ---数据传输
    java.net --- 网络通信,后面介绍
    java.nio --- 高并发,服务器有关的包,双十一的时候抢购处理这些数据
    java.text --- 格式化,超市去买东西,结账系统,8.88,* 3 * 0.88 出现 4 位小数,现实生活中是两位,就用这个包
     
    总结:java.lang 包下的类以及同包类在使用的时候可以不用导包
     
    包就是一个用来声明和导入的,现阶段还没有什么更多的知识介绍,以后遇到了,再介绍吧!!接下来谈谈垃圾分代回收方面的知识:
     
    垃圾分代回收机制
    (针对的是堆内存。)
    java 中的每种数据类型大小都是确定的,所以所有的内存是由 Java 自己进行分配,意味着内存的管理和回收也是由 JVM 自己进行 --- 在 Java 中一旦产生内存问题导致程序员无法处理。(在 C 和 C++ 中就是自己来定义管理的)理论上在正常情况下 Java 中的堆内存是足够使用的 --- 当堆内存使用的负荷量(堆内存的 70 %,可能有的时候又不一样)超过一定限度的时候,会启动垃圾回收器(Garbage Collector --- GC)进行堆内存的回收释放 --- 
    C int 只要不超过 4 个字节就行。
    int i = 3;   --- 3
    int j = i;   --- 1
     
      
    扩展:eden:from :to = 8:1:1
    上图的简介:对象刚创建的时候是先放入新生代中的伊甸园区;如果在伊甸园区经过一次回收依然存在,那么将这个对象挪到幸存区,在幸存区中经过多次回收这个对象依然存在则挪到老生代。在回收的时候先回收新生代,如果新生代回收之后的内存足够使用则不扫描老生代。老生代的扫描频率要低于新生代
    发生在新生代的回收 --- 初代回收 minor gc
    发生在老生代的回收 --- 完全回收 full gc
    (对于双十一,购物完之后就产生和销毁,应该将新生代设置得大一点,方便对象的创建)
    扩展:对象创建完成之后会先试图放入新生代;如果新生代经过回收之后也放不开,则直接试图将该对象放入老生代。老生代如果也放不开,则会出现错误 --- OutOfMemoryError.
  • 相关阅读:
    ZZ: kvm qemu kqemu qemu-kvm libvirt
    ZZ:爬虫
    Mac下安装及配置Appium环境
    badboy使用手册
    如何正确做 Web端压力测试?
    关于web页面性能测量指标与建议
    Pycharm的使用一
    如何下载安装Python
    apache jmeter下载与安装
    但行其事,不问前程
  • 原文地址:https://www.cnblogs.com/tangdiao/p/9470431.html
Copyright © 2011-2022 走看看