JAVA——健忘年轻人笔记

  1. 类内若未定义构造函数,编译器会隐式定义默认构造函数(是一个无参构造函数),来调用父类无参构造函数,若此时父类无对应函数,则报错。若无父类,则其隐式继承自 Object 类,该类有无参构造函数(隐式塞个父亲???hardcore)。(34点有更详细说明

  2. JAVA中,对象、数组都是引用类型,一经初始化赋值就无法再改变

  3. new 关键字实例化一个类(按类定义分配一份内存),并返回内存地址的引用,同时,调用构造函数(执行初始化操作)。

  4. GC(Garbage Collector):垃圾回收机制,当JRE检测到创建出的对象不再被引用时,会自动销毁该对象,回收其内存。

  5. class可以作为方法的返回类型,此时,方法的实际返回对象可以是该class的某对象,也可以是该class子类的某对象,这种操作叫covariant return type。interface也可以是返回类型,这种情况下,方法的实际返回对象必须是该interface的某实现类的对象。

  6. this是current object的一个引用,其一个常见的使用场景是,当方法的parameter屏蔽(shadow)了fields时,通过this.field绕过该屏蔽。此外,还可在类的构造函数内使用this调用该类的另一构造函数,此时,该调用语句必须位于主调构造函数的第一行.

    public class Rectangle {
        private int x, y;
        private int width, height;
            
        public Rectangle() {
            this(0, 0, 1, 1);
        }
        public Rectangle(int width, int height) {
            this(0, 0, width, height);
        }
        public Rectangle(int x, int y, int width, int height) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }
        ...
    }
    
  7. package是相关类构成的组。若未声明访问修饰符,则默认为package-private,即包内公开。

  8. class的访问修饰符只有public与package-private,而class的成员,另外多了protected与private两个修饰符。

  9. static修饰methods、fields,表明其为class级别,而非instance级别,class级别的方法无法直接访问instance variables or methods,必须通过object reference来间接访问。final修饰fields,表明其cannot be reassigned,修饰methods,表明其不可被子类override,修饰class,表明其不可扩展出子类

    class methods无法直接访问instance成员是很好理解的,因为class methods只有一份,而instance有很多份,从class->到instance是指向不明的。同时,class在使用时可以被虚拟机加载,但instance必须要手动new,无法保证在访问static成员时,有instance。

  10. 类可以作为类的成员类型,即nested class。此时,若nested class加了static限定,则无权限访问enclosing class(外部类,也即outer class)的其他成员。而若未加static(即 inner class),则视为enclosing class的一个成员,可以访问其他private成员(换句话讲,此时的inner class使用不当会成为一个后门,提供间接访问private成员的途径)。

    也就是说,加了static后,该类在级别上其实等同于另一个外部类,只不过为了便于管理,才使用nested class的方式封装在enclosing class内。

    inner class依托于outer class的instance存在,故其内部无法再定义static成员。inner class是class内部的class,即蓝图中的蓝图,故必须先将outer class实例化后,才可通过outer object间接实例化

    简单来讲,inner class双重虚幻。

    OuterClass.InnerClass innerObject = outerObject.new InnerClass();
    
  11. for-each loop简洁的遍历collection中的元素,并do sth。

    for (certainClassInCollection c : certainCollection) {
    	action...
    }
    

    其实质是将iterator的操作隐藏给编译器。

    局限性:在遍历时(例如数组)无法修改元素值,因其原理类似于将集合拷贝了一份,修改(或赋值)的对象不是本体

  12. 接口做形参,在实际调用方法时,要求传入的实参实现了接口
    此外,在方法内部调用形参类内的成员方法前,要先将接口类型的形参进行强制类型转换,由接口类型转换为实际的实参类类型。这么做是因为编译器并不知道会传入的实参的具体类型。而若是 interface certainInterface = new certainClassOfInterface() 的方式,则后续不需要类型转换即可直接调用接口实现类的类内方法。

    public int isLargerThan(Relatable other) {
        RectanglePlus otherRect = (RectanglePlus)other;
    	otherRect.getArea();
    }
    

    When you define a new interface, you are defining a new reference data type.

  13. 接口无法实例化,只能被实现或扩展(被其他接口扩展)。

  14. 接口只能包含constants, default / static / abstract methods, and nested types(例如enum)。接口中的方法如果不是default或static,则隐式地是abstract。接口中的所有方法都隐式地是public。接口中的常量隐式地是public, static, final

    An abstract method is a method that is declared without an implementation (without braces, and followed by a semicolon),

  15. 一个接口可以扩展自任意多的接口,而类只能扩展自一个其他类。

  16. 函数式接口(functional interface)是内部的抽象方法只有一个的接口,当某函数的形参是函数式接口时,可以使用lambda表达式

  17. 为接口新增方法,同时不影响其他已实现类的操作方式:定义新的扩展(extends)接口;将旧接口的新增方法限定为 default

  18. 扩展包含default methods的接口时,可以无操作(自动继承该default methods),或是不带default限定地再次声明(新接口内其变为抽象方法),或是带default地重写(新接口内覆盖)。

  19. enum自动继承自Enum类,因此类中的enum数据其实是嵌入类。enum数据会被编译器自动地添加values()方法(返回一个包含枚举所有值的数组)

  20. 构造函数不是类成员,无法被继承

  21. public、protected 限定的成员一定会被继承,而 package-private 修饰的成员则需要在同一包内才会被继承。即,成员的继承需满足父类与子类间的可见性
    父类的成员一定会被子类继承(详见34)。

  22. 对象类型检查操作符:instanceof.

    if (obj instanceof MountainBike) {
        MountainBike myBike = (MountainBike)obj;
    }
    
  23. 对于类,JAVA中不允许多重继承,主要是为了避免可能会产生的不同超类初始化同一field时,优先级判定的问题。而接口没有fileds,故允许多重继承。而接口的多重继承特性又可能会造成方法的重名问题,default methods则加大了这种问题发生的概率。

    复习一下,An object stores its state in fields, which are defined in classes

  24. method signature:name、number and the type of its parameters.

  25. 接口中的static methods无法被继承

  26. 子类继承父类,有可能会hide static methods & override instance methods。而两者的区别在于,调用override的instance methods时,被调用的是子类中的那个,而调用hide的static methods时,要看当前调用是通过父类还是子类。毕竟,static method是独立存在于 class 而非 instance 的。(这里举的例子里还体现了多态:由于myAnimal引用的object是Cat,故调用instance methods时,输出cat)

    class Animal {
        public static void testClassMethod() {
            System.out.println("The static method in Animal");
        }
        public void testInstanceMethod() {
            System.out.println("The instance method in Animal");
        }
    }
    
    class Cat extends Animal {
        public static void testClassMethod() {
            System.out.println("The static method in Cat");
        }
        public void testInstanceMethod() {
            System.out.println("The instance method in Cat");
        }
    
        public static void main(String[] args) {
            Cat myCat = new Cat();
            Animal myAnimal = myCat;
            myCat.testInstanceMethod();// Cat
            myCat.testClassMethod();// Cat
            Cat.testClassMethod();// Cat
    
            myAnimal.testInstanceMethod();// Cat
            myAnimal.testClassMethod();// Animal
            Animal.testClassMethod();// Animal
    
        }
    
  27. 当继承的父类中的instance methods与实现的接口中的default methods(or abstract methods)冲突时,优先调用instance methods.

    class Horse {
        public String identifyMyself() {
            return "I am a horse.";
        }
    }
    interface Flyer {
        default public String identifyMyself() {
            return "I am able to fly.";
        }
    }
    interface Mythical {
        default public String identifyMyself() {
            return "I am a mythical creature.";
        }
    }
    class Pegasus extends Horse implements Flyer, Mythical {
        public static void main(String... args) {
            Pegasus myApp = new Pegasus();
            System.out.println(myApp.identifyMyself());//I am a horse
        }
    }
    
  28. 当类实现的多个接口有共同祖先时,若default methods被其中之一override,则优先使用override后的default methods.

    interface Animal {
        default public String identifyMyself() {
            return "I am an animal.";
        }
    }
    interface EggLayer extends Animal {
        default public String identifyMyself() {
            return "I am able to lay eggs.";
        }
    }
    interface FireBreather extends Animal {
    }
    class Dragon implements FireBreather, EggLayer {
        public static void main (String... args) {
            Dragon myApp = new Dragon();
            System.out.println(myApp.identifyMyself());\\I am able to lay eggs
        }
    }
    
  29. 继承时,方法的访问限定符可以变得更加开放,但不能变得更保守

  30. 多态(Polymorphism):The Java virtual machine (JVM) calls the appropriate method for the object that is referred to in each variable. It does not call the method that is defined by the variable’s type. This behavior is referred to as virtual method invocation and demonstrates an aspect of the important polymorphism features in the Java language.

    //本例是残缺代码,其中 MountainBike、RoadBike 继承了 Bicycle,
    //并各自实现了自己的 printDescription()
    public class TestBikes {
      public static void main(String[] args){
      
        Bicycle bike01, bike02, bike03;
    
        bike01 = new Bicycle(20, 10, 1);
        bike02 = new MountainBike(20, 10, 5, "Dual");
        bike03 = new RoadBike(40, 20, 8, 23);
    
        bike01.printDescription();//Bicycle.printDescription()
        bike02.printDescription();//MountainBike.printDescription()
        bike03.printDescription();//RoadBike.printDescription()
      }
    }
    
  31. 子类中的fields若与父类中的fileds重名,则会hide掉父类的fields,即使类型不同

  32. 关键字super:通过super可调用父类被override的methods,或被hide的fileds(although hiding fields is discouraged)。相比于this绕过了当前方法的shadow parameter,super绕过的是当前子类重写或隐藏的父类methods/fields。

    public class Superclass {
    
        public void printMethod() {
            System.out.println("Printed in Superclass.");
        }
    }
    public class Subclass extends Superclass {
    
        // overrides printMethod in Superclass
        public void printMethod() {
            super.printMethod();
            System.out.println("Printed in Subclass");
        }
        public static void main(String[] args) {
            Subclass s = new Subclass();
            s.printMethod();    
        }
    }
    
  33. super() 可调用父类的无参构造函数,super(parameter list)可调用父类对应的有参构造函数,(用法同于this(),参见本文第6条)。

  34. 如果子类没有显式地调用父类的构造函数,编译器会自动插入父类的无参构造函数,而此时若父类没有无参构造函数,则会报错。Object 作为最高类,含有无参构造函数,故若Object是唯一父类,则不会有问题。此外,由此可看出,调用子类的构造函数必定引发连锁反应(constructor chaining)。

    此处可以看出,子类的构造是以父类为基础的,可以理解为:在创建子类实例时,先调用父类构造函数创建一个父类实例,之后再创建子类扩展的成员。也就是说,父类的成员会被子类全部继承拥有,而private等限定词的作用,是可见性。若父类中没有对子类可见的方法,来让子类访问使用(setter,getter等)父类的私有成员,则子类仅拥有该成员(打不开的保险柜,甩不掉的累赘)。

    又,和1进行总结:
    1.当子类父类均未定义构函,编译器隐式调用父类无参构函(object是爷爷),一切如常;
    2.当父类有有参构函,无无参构函,子类未显式调用父类有参构函时,报错;退一步讲,即使子类显式调用有参构函,程序无错,但需要保证后续的子孙类 都有 显式调用父类有参构函的好习惯,且不定义无参构函。(饮鸩止渴)
    3.所以应有随手创建不做事的无参构函的好习惯!

    复习一下,Object是所有无显式父类的类的隐式父类,换句话讲,要么你祖宗是Object,要么你爹是Object…
    In the absence of any other explicit superclass, every class is implicitly a subclass of Object.

  35. 父类中protected限定的 members,可以被子类跨包继承,但不能被跨包访问(即使是子类)。也就是说,在跨包的状态下,子类仅能调用自己继承的protected members,而无法访问父类实例的protected members。而若在同一包内,那protected members的可继承性与可访问性等同于package-private。

    一句话,相比于package-private,protected的作用仅体现在可让子类跨包继承

    最终版:此处的跨包继承是笔者自创的说法,该说法是不严谨的,因为父类的任何成员、方法都可被任何包的子类继承拥有。但是,限定词限定了类内成员在不同作用域的可见性。protected 是public与private的折中,在跨包的状态下,父类即想要给子类一个成员(public的开放性),又不想让子类调用父类自己的对应成员(private的隐私性),于是有了protected。

  36. 若想让类对象能被外界调用 clone() 复制,必须实现Cloneable接口(标记接口)。同时,将继承的 clone() 重写,限定为public。Object.clone() 仅实现浅拷贝

  37. Object类中,包含了public的getClass()方法,可以返回一个Class类该类中包含了若干方法可以获取当前对象的信息,如getSimpleName(),getName(),getSuperclass(),getInterfaces()等。

  38. 类实现接口,可以不实现所有方法,此时需要将类限定为abstract class。

  39. equals():到底还是遇到了这个坑。需要辨明的是 equals 与 = = 两者之间的区别。
    = =比较的是两者是否为同一个对象或指向同一个对象(对于引用类型而言),使用new关键字一定会创建一个新对象
    equals()作为一个在Object类中定义了的方法(Object中通过= =实现equals),可被其他子类重写。因此要具体分析对应类的实际equals()实现
    String属于引用类型,其重写了equals,比较对应的内容是否相等。
    此外,由于java有常量池的概念,不同类型在一定范围内的数会被存储起来,以后除非使用了new,否则直接定义的重复常量不再创建新对象,而是指向常量池中已有对象。

  40. 重写equals()方法就必须重写hashCode()的原因:必须保证对于equals的对象,有相等的hashcode(反之不然,后者是前者的必要不充分条件)。

  41. 通过在方法中返回this,可以实现方法的链式调用

  42. JDK8开始,static变量存储在当前类的Class对象中而Class对象位于堆中

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值