Java基础知识干货

作者: fanyank | 来源:发表于2017-10-27 17:35 被阅读40次

    这个是我个人阅读《Java核心技术》和《Java编程思想》总结出来的笔记,清晰明了,但是没有细致讲解,如果碰到疑惑的地方,可以另行查阅。

    封装

    • 从形式上看,封装将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式
    • 实现封装的关键在于绝对不能让类中的方法直接访问其他类的实例域,程序仅通过对象的方法同对象的数据进行交互

    对象变量和对象

    Date deadline;   //没用引用任何对象
    deadline = new Date();  //使用新构造的对象初始化变量
    Date birthday = deadline; //引用一个已经存在的变量
    
    变量和对象
    • 一个对象变量并没有实际包含一个对象,而仅仅引用一个对象
    • 所有的Java对象都存储在

    更改器方法和访问器方法

    • 更改器方法:
      调用该方法后,对象的状态会改变
    • 访问器方法:
      只访问对象而不修改对象的方法(如toUpperCase)

    隐式参数与显式参数

    public void raiseSalary(double byPercent) {
      double raise = this.salary * byPercent / 100;
      this.salary += raise;
    }
    

    函数的参数为 显式参数,this 为 隐式参数

    final实例域

    final 修饰符大都应用于基本类型域,或不可变类的域(类中的每个方法都不会改变其对象,这种类就是不可变的类,如String),对于可变的类,所传达的意思为该变量不会再引用其他对象,但这个对象仍然可变(如StringBuilder)

    方法参数

    • 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)
    • 一个方法可以改变一个对象参数的状态
    • 一个方法 不能让对象参数引用一个新的对象
    • 对象引用实际上是按值传递的

    继承

    1. 子类继承父类的成员变量
      当子类继承了某个类之后,便可以使用父类中的成员变量,但并不是完全继承父类的成员变量
    • 能够继承父类的public和protected成员变量;不能够继承父类的private成员变量;
    • 对于父类的包访问权限成员变量,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;
    • 对于子类可以继承的父类成员变量,如果在子类中出现了同名称的成员变量,则会发生隐藏现象,即子类的成员变量会屏蔽掉父类的同名成员变量。如果要在子类中访问父类中同名成员变量,需要使用super关键字来进行引用。
    1. 子类继承父类的方法
      同样的,子类也不是完全继承父类的所有方法
    • 能够继承父类的public和protected成员方法;不能够继承父类的private成员方法;
    • 对于父类的包访问权限成员方法,如果子类和父类在同一个包下,则子类能够继承;否则,子类不能够继承;
    • 对于子类可以继承的父类成员方法,如果在子类中出现了同名称的成员方法,则称为覆盖,即子类的成员方法会覆盖掉父类的同名成员方法。如果要在子类中访问父类中同名成员方法,需要使用super关键字来进行引用。

    注意:隐藏和覆盖是不同的。隐藏是针对成员变量和静态方法的,而覆盖是针对普通方法的。

    引用自http://www.cnblogs.com/dolphin0520/p/3803432.html

    重载

    • 多个方法有相同的名字,不同的参数(与域修饰符,返回值无关)
    • Java允许重载任何方法
    • 要完整的描述一个方法,需要指出方法名以及参数类型,这叫做方法的签名,返回类型不是方法签名的一部分(这意味不能有两个名字,参数相同但是返回值不同的方法)

    无参构造器

    只有当一个类没有任何构造器时,系统才会给一个默认的无参构造器,该构造器将实例域设置为默认值(null,false,0)

    如果在源文件中没有 package 语句,这个源文件中的类将被放置在一个默认包中,默认包是一个没有名字的包

    this和super

    1. this有两个用途:
    • 引用隐式参数
    • 调用该类其他的构造器(调用其他构造器的语句应作为该构造器的第一条语句出现)
    1. super有两个用途
    • 调用超类方法(为了区分本类方法和超类方法)
    • 调用超类的构造器

    什么是多态

    一个对象变量可以被指示为多种实际类型的现象被称为 多态

    class Base{
      int count=2;
      public void display() {
        System.out.println(this.count);
      }
     }
    
    public class Derived extends Base{
    int count=20;
    
    @Override
    public void display() {
      System.out.println(this.count);
    }
    
    public static void main(String[] args) {
        Base base = new Derived();
        System.out.println(base.count);      //2
        base.display();                      //20
    
      }
    }
    
    

    要弄清楚这个过程,首先需要知道什么叫做绑定
    将一个方法调用和一个方法主体关联起来叫做 绑定,程序执行前进行绑定,叫做前期绑定(C语言只有一个方法调用,就是前期绑定),上述程序之所以让人迷惑,就是因为前期绑定,为了解决这种冲突,引出了后期绑定。
    后期绑定的含义就是运行时根据对象的类型进行绑定,后期绑定也叫做动态绑定,如果一种语言想实现动态绑定,那么就必须有某种机制。以便在运行时判断对象的类型。
    Java的做法是除了 static和final,其他所有的方法全部都是动态绑定。

    如你所见,base变量在运行期间是Derived类的行为,但是访问base域时却是Base的域,这是因为动态绑定的存在,使得原本Base类的普通方法(非private,static::注:非private是因为private被自动认为是final方法)被覆盖掉,所以表现出来的行为就是Derived类的行为。

    什么是动态绑定

    见上

    在覆盖一个方法时,子类方法不能低于父类方法的可见性

    抽象类和抽象方法

    • 包含一个或多个抽象方法的类必须声明为抽象类,但是抽象类不一定需要包含抽象方法
    • 抽象类可以包含具体的数据和方法
    • 抽象方法充当着 占位的角色,他们的具体实现在子类中,子类在继承抽象类是面临两个选择:
    1. 子类仍然标记为抽象类
    2. 子类不被标记为抽象类,但是需要 定义全部的抽象方法
    • 不能构造抽象类的对象,但是可以声明抽象类的变量

    在Java中,只有基本类型不是对象,所有的数组类型(包括基本类型数组)都扩展了Object类

    hashcode

    • 散列码(hash code)是由对象导出的一个整型值
    • 字符串的散列码由内容导出,如果两字符串内容相同,那么其导出的散列码也相同
    • Object类默认hashcode()方法导出对象的存储地址

    包装器对象

    ==和equals

    需要注意各种包装器中valueOf()方法的实现,其中Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的,Double、Float的valueOf()方法的实现是类似的。

    Integer、Short、Byte、Character、Long这几个类的valueOf方法实现如下,该种实现会使数值在[-128,127]之间的对象指向同一块内存区域。

    public static Integer valueOf(int i) {
            if(i >= -128 && i <= IntegerCache.high)
                return IntegerCache.cache[i + 128];
            else
                return new Integer(i);
    }
    

    Double、Float的valueOf()方法的实现如下,每次都会返回一个新对象。

    public static Double valueOf(double d) {
           return new Double(d);
    }
    

    那么布尔类型的valueOf()实现是怎样的呢?

    public static Boolean valueOf(boolean b) {
            return (b ? TRUE : FALSE);
    }
    

    这就意味着下面这段代码输出为true,true。

    public class Main {
        public static void main(String[] args) {
            Boolean i1 = false;
            Boolean i2 = false;
            Boolean i3 = true;
            Boolean i4 = true;
    
            System.out.println(i1==i2);
            System.out.println(i3==i4);
        }
    }
    

    获取Class对象

    1. Random generator = new Random();
       Class cl = generator.getClass();
    
    2. String className = "java.util.Random";
       Class cl = Class.forName(className);
    
    3. Class cl = Random.class;
    

    获取对象的实例

    Object m = Class.forName(s).newInstance();
    

    垃圾回收

    • 使用 finalize() 方法释放"特殊的内存区域",通常该区域为其他语言申请得来的内存。
    • 通过 new 操作符 创建出来的对象Java会自动回收。

    接口中的自动声明

    • 接口中的所有方法自动属于 public,不必显示声明,但在实现接口提供的方法时,必须把方法显示的声明为 public
    • 接口中的域将被自动设为 public static final

    每个类只能有一个超类,但是却可以实现多个接口

    接口的默认实现

    public interface Comparable<T> {
      default int compareTo(T other) {
        return 0;
      }
    }
    

    解决接口冲突

    • 情景一: A接口和B接口中都有一个fun()方法,但返回值不同,那么C类就不可能同时实现A接口和B接口,因为接口的设计本身就存在问题

    • 情景二: A接口和B接口中都有一个fun()方法,返回值和方法参数都相同,那么C类就可以同时实现A接口和B接口,即使可以实现,但是接口的设计还是存在问题

    • 情景三: A接口中有fun()方法,超类F中也有fun()方法,那么C类同时继承F类并实现A接口时,会覆盖超类中的fun()方法而不会去实现A接口中的fun()方法(类优先的原则)

    实现Comparator接口来进行排序

    Comparator接口中比较器声明如下:

    public interface Comparator<T> {
      int compare(T first,T second);
    }
    

    实现按长度比较字符串,可以定义一个Comparator<String>类

    class LengthComparator implments Comparator<String> {
      public int compare(String s1,String s2) {
        return s1.length() - s2.length();
      }
    }
    

    实际调用:

    //1.普通调用
    Comparator<String> comp = new LengthComparator();
    if(comp.compare(word[i],word[j]) > 0) {
      ...
    }
    
    //2.比较器调用
    Arrays.sort(arr,new LengthComparator());
    

    使用lambda表达式

    上述例子可以修改如下:

    Arrays.sort(arr,(s1,s2) -> s1.length() - s2.length());
    

    lambda表达式的作用域

    lambda表达式有三个组成部分:

    • 一个代码块
    • 参数
    • 自由变量的值,这里指非参数而且不在代码中定义的变量(主要讨论它)
    1. 要确保该值只能被引用,而不会被改变
    2. 该值在lambda外部必须是最终变量
    3. lambda表达式的体与嵌套块有相同的作用域,要避免命名冲突
    //该例子存在命名冲突
    Path first = Path.get("/usr/bin");
    Comparator<String> comp = (first,second) -> first.length() - second.length();
    
    1. 在lambda表达式中使用this关键字时,this所指与平常无异(即this为创建lambda表达式方法的对象)

    什么是函数式接口

    对于只有一个抽象方法的接口,需要这种接口对象时,就可以提供一个lambda表达式,这种接口成为 函数式接口

    Java基础知识干货2传送门->http://www.jianshu.com/p/9bb6827a768c

    相关文章

      网友评论

        本文标题:Java基础知识干货

        本文链接:https://www.haomeiwen.com/subject/aerdpxtx.html