Java基础

2018-08-05  本文已影响0人  greyeagle

一、数据类型

包装类型

八个基本类型:

注:String不是基本类型。每个基本类型都有其对应的包装类型,基本类型与包装类型之间的转换称之为装箱与拆箱,但这种操作一般是是自动完成的。

Integer x = 1;  //装箱
int y = x;      //拆箱

缓存池

new Integer(123)与Integer.valueOf(123)是不同的,前者会创建一个Integer对象,而后者会使用缓存对象,也就是多次使用Integer.valueOf(123)获得的Integer对象很可能是同一对象。举例如下:

Integer x = new Integer(123);
Integer y = new Integer(123);
System.out.println(x == y);    // false
Integer z = Integer.valueOf(123);
Integer k = Integer.valueOf(123);
System.out.println(z == k);   // true

注:在自动装箱的过程中编译器其实就是调用了valueOf()方法,因此多个Integer实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。

二、String

概述

首先看一下String源码的开头部分

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

String类被声明为final,说明不可被继承。
内部使用char数组存储数据,数组也被声明为final,说明数组初始化后也就不能被引用其他数组了,而且查看API文档可知,String类内部方法中也没有改变value数组的方法,因此String具有不可变性。

不可变的好处

1.可以缓存hash值

String的hash值经常被使用,例如String用作HashMap的key。不可变性使得hash值不会发生改变,所以只需要计算一次即可。

2.String Pool的需要

如果一个String已经被创建过,就会被存储到字符串常量池中,将来就会从String Pool中应用。只有 String 是不可变的,才可能使用 String Pool。

3.安全性

String常作为参数,String的不可变性保证的参数不会被改变。比如:在如下这种情况下结果输出仍然为"1"。

public static void main(String[] args){
        String s = "1";
        changeStr(s);
        System.out.println(s);
    }

public static void changeStr(String s){
        s = "2";
    }

4.线程安全

String的不可变性天生具备线程安全,可以在多个线程中安全使用。

String,StringBuffer,StringBuilder

1.可变性

2.线程安全

String.intern()

当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。

它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。

String s1 = new String("1");
String s2 = "1";
System.out.println(s1==s2);  //false
System.out.println(s1==s1.intern());  //true

上面有两种创建String对象的方法,第二种形式创建的字符串实例会自动将对象放入字符串常量池(String Pool)中。所以二者对象地址不同,s1==s2就为false。

三、继承

访问权限

子类继承父类,表示子类会继承父类的一切,即父类的所有成员变量及方法。但是,我们会发现,有部分父类的方法和变量我们是无法进行访问或调用的,这就与它们的访问权限相关了。

  1. private修饰词,表示成员是私有的,只有自身可以访问;
  2. protected,表示受保护权限,体现在继承,即子类可以访问父类受保护成员,同时相同包内的其他类也可以访问protected成员。
  3. 无修饰词(默认),表示包访问权限(friendly, java语言中是没有friendly这个修饰符的,这样称呼应该是来源于c++),同一个包内可以访问,访问权限是包级访问权限;
  4. public修饰词,表示成员是公开的,所有其他类都可以访问;

注:子类重写继承的方法时,不可以降低方法的访问权限,子类继承父类的访问修饰符要比父类的更大,也就是权限更加开放。

抽象类与接口

1.抽象类

抽象类和抽象方法都使用 abstract 进行声明。抽象类一般会包含抽象方法,抽象方法一定位于抽象类中。抽象类和普通类最大的区别是,抽象类不能被实例化,需要继承抽象类才能实例化其子类。

public abstract class AbstractClassExample {

    protected int x;
    private int y;

    public abstract void func1();

    public void func2() {
        System.out.println("func2");
    }
}
public class AbstractExtendClassExample extends AbstractClassExample{
    @Override
    public void func1() {
        System.out.println("func1");
    }
}
// AbstractClassExample ac1 = new AbstractClassExample();// 'AbstractClassExample' is abstract; cannot be instantiated
AbstractClassExample ac2 = new AbstractExtendClassExample();
ac2.func1();

2.接口

接口是抽象类的延伸,在 Java 8 之前,它可以看成是一个完全抽象的类,也就是说它不能有任何的方法实现。

接口的成员(字段+方法)默认都是public的,并且不允许定义为 private 或者 protected。

接口的字段默认都是 static 和 final 的。

public interface InterfaceExample {
    void func1();

    default void func2(){
        System.out.println("func2");
    }

    int x = 123;
    // int y;                // Variable 'y' might not have been initialized
    public int z = 0;       // Modifier 'public' is redundant for interface fields
    // private int k = 0;   // Modifier 'private' not allowed here
    // protected int l = 0; // Modifier 'protected' not allowed here
    // private void fun3(); // Modifier 'private' not allowed here
}

/*************************************************************************/
public class InterfaceImplementExample implements InterfaceExample {
    @Override
    public void func1() {
        System.out.println("func1");
    }
}

/************************************************************************/
// InterfaceExample ie1 = new InterfaceExample(); // 'InterfaceExample' is abstract; cannot be instantiated
InterfaceExample ie2 = new InterfaceImplementExample();
ie2.func1();
System.out.println(InterfaceExample.x);

3.比较

参数 抽象类 接口
默认的方法实现 它可以有默认的方法实现 接口完全是抽象的。它根本不存在方法的实现
实现 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现
构造器 抽象类可以有构造器 接口不能有构造器
与正常Java类的区别 除了你不能实例化抽象类之外,它和普通Java类没有任何区别 接口是完全不同的类型
访问修饰符 抽象方法可以有public、protected和default这些修饰符 接口方法默认修饰符是public。你不可以使用其它修饰符。
main方法 抽象方法可以有main方法并且我们可以运行它 接口没有main方法,因此我们不能运行它。
多继承 抽象方法可以继承一个类和实现多个接口 接口只可以继承一个或多个其它接口
速度 它比接口速度要快 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
添加新方法 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 如果你往接口中添加方法,那么你必须改变实现该接口的类。

4.使用选择

使用抽象类:

使用接口:

在很多情况下,接口优先于抽象类,因为接口没有抽象类严格的类层次结构要求,可以灵活地为一个类添加行为。并且从 Java 8 开始,接口也可以有默认的方法实现,使得修改接口的成本也变的很低。

super

重写与重载

上一篇 下一篇

猜你喜欢

热点阅读