Java 基础
Posted 说到做到_我的忍道
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 基础相关的知识,希望对你有一定的参考价值。
一、数据类型
1. 包装类型
boolean/1
byte/8
char/16
short/16
int/32
float/32
long/64
double/64
装箱与拆箱
Integer x =2 // 装箱
int y =2;//拆箱
2. 缓存池
new Integer(123)与Integer.valueOf(123)的区别在于:
new Integer(123)每次都会创建一个对象
Integer.valueOf(123)会使用缓存池中的对象,多次调用会取得同一个对象的引用。
Integer x = new Integer(123);
Integer y = new Integer(123);
System.out.println( x==y );
Integer m = Integer.valueOf(123);
Integer k = Integer.valueOf(123);
System.out.println( m == k);
编译器会在自动装箱过程中调用valueOf()方法, 因此多个Integer实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。
基本类型对应的缓冲池如下:
boolean : true false
all byte values
short/int values between -128 and 127
char in the range \\u0000 to \\u007F
在使用这些基本类型对应的包装类型时,就可以直接使用缓冲池的对象。
二、String
概览
String 被声明为final, 因此它不可被继承。
value 数组被声明为final, 这意味着value数组初始化之后就不能再引用其他数组。并且String内部没有改变value数组的方法,因此可以保证String不可变。
不可变的好处
1. 可以缓存hash值
因为String的hash值经常被使用,例如String用做HashMap的key。不可变的特性可以使得hash值也不可变,因此只需要进行一次计算。
2. String Pool 的需要
如果一个String对象已经被创建过了,那么就会从String Pool中取得引用。只有String是不可变的,才可能使用String Pool。
3. 安全性
String经常作为参数,String不可变性可以保证参数不可变。例如再作为网络连接参数的情况下如果String是可变的,那么再网络连接过程中,String被改变,改变String对象的那一方以为现在连接的是其他主机,而实际情况不一定是。
4. 线程安全
String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
String, StringBuffer and StringBuilder
1. 可变性
String不可变
StringBuffer和StringBuilder可变
2. 线程安全
String不可变,所以线程安全
StringBuilder不是线程安全的
StringBuffer是线程安全的,内部使用synchronized进行同步
String Pool
字符串常量池(String Pool)保存着所有字符串字面量, 这些字面量在编译时期就确定。不仅如此,还可以使用String的intern()方法在运行过程中讲字符串添加到String Pool中。
当一个字符串调用intern()方法时,如果String Pool中已经存在一个字符串和该字符串值相等(使用equals()方法进行确定),那么就会返回String Pool中字符串的引用;否则,就会在String Pool中添加一个新的字符串,并返回这个新字符串的引用。
new String("abc")
使用这种方式一共会创建两个字符串对象(前提是String Pool中还没有“abc”字符串对象)。
“abc”属于字符串字面量,因此编译时期会在String Pool中创建一个字符串对象,指向这个“abc”字符串字面量;
而使用new的方式会在堆中创建一个字符串对象。
三、运算
参数传递
Java的参数是以值传递的形式传入方法中,而不是引用传递。
float 与 double
Java不能隐式执行向下转型,因为这会使得精度降低。
1.1 字面量属于double类型,不能直接将1.1直接赋值给float变量,因为这是向下转型。
1.1f 字面量才是float类型
隐式类型转换
因为字面量1是int类型,他比short类型精度要高,因此不能隐式地将int类型转型为short类型。
但是使用 += 或者 ++ 运算符可以执行隐式类型转换。
switch语句可以使用String对象。
四、继承
访问权限
private、protected和public,如果不加修饰符,表示包级可见。
可以对类或类中的成员加上修饰符。
类可见表示其他类可以使用这个类创建实例对象。
成员可见表示其他类可以用这个类的实例对象访问到该成员。
protected用于修饰成员,表示在继承体系中成员对于子类可见,但是这个访问修饰符对于类没有意义。
设计良好的模块会隐藏所有的实现细节,把他的API与他的实现清晰地隔离开来。模块之间只通过他们的API进行通信,一个模块不需要知道其他模块的内部工作情况,这个概念被称为信息隐藏或封装。因此访问权限应当尽可能地使每个类或者成员不被外界访问。
如果子类的方法重写了父类的方法,那么子类中该方法的访问级别不允许低于父类的访问级别。这是为了确保可以使用父类实例的地方都可以使用子类实例,也就是确保满足里式替换原则。
字段绝不能是公有的,因为这么做的话就失去了对这个字段修改行为的控制,客户端可以对其随意修改。
抽象类与接口
1. 抽象类
抽象类和方法都用abstract关键字。抽象类包含抽象方法,抽象方法包含于抽象类中。
抽象类和普通类最大的区别就是,抽象类不能被实例化,需要继承才能实例化其子类。
2. 接口
可以有默认的方法实现,
接口的成员(字段和方法)默认都是public的,并且不允许定义为private或者protected。
接口的字段默认都是static和final的。
3. 比较
从设计层面上看,抽象类提供了一种IS-A关系,那么就必须满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种LIKE-A关系,他只是提供一种方法实现契约,并不要求接口和实现接口的类具有IS-A关系。
从使用上来看,一个类可以实现多个接口,但是只能继承一个抽象类。
接口的字段只能是static和final的,而抽象类的字段没有这种限制。
接口的成员只能是public的,而抽象类的成员可以有多种访问权限。
4. 使用选择
使用接口:
需要让不相关的类都实现一个方法,例如不相关的类都可以实现Compareable接口中的compareTo()方法;
需要使用多重继承
使用抽象类:
需要在几个相关的类中共享代码
需要能控制继承来的成员的访问权限,而不是都为public
需要继承非静态和非常量字段
在很多情况下,接口优先于抽象类。因为接口没有抽象类严格的类层次结构要求,可以灵活的为一个类添加行为。并且从Java8开始,接口也可以有默认的方法实现,使得修改接口的成本变得很低。
super
访问父类的构造函数:可以使用super()访问父类的构造函数
访问父类的成员:super引用父类方法
重写与重载
重写(Overload)
存在于继承体系中,指子类实现了一个于父类在方法声明上完全相同的一个方法
满足里式替换原则:
1. 子类访问权限必须大于等于父类方法
2. 子类方法的返回类型必须是父类方法返回类型或其子类
使用@Override, 可以让编译器帮助检查是否满足
重载(Overload)
存在于同一个类中,指一个方法与已经存在的方法名称一样,但是参数类型、个数、顺序至少一个不同
注意:只有返回值不同不算重载
五、Object通用方法
equals()
对于基本类型, == 判断两个值是否相等,基本类型没有equals()方法
对于引用类型, == 判断两个变量是否引用同一个对象,而equals()判断引用的对象是否等价
hashCode()
hashCode() 返回散列值,而equals()是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。
在覆盖equals()方法时应当总是覆盖hashCode()方法,保证等价的两个对象散列值也相等。
toString()
默认返回xxx@4554716c这种形式,其中@后面的数值为散列码的无符号十六进制表示。
clone()
1. cloneable
clone() 是 Object的protected方法,它不是public, 一个类不显式去重写clone(),其他类就不能直接去调用该类实例的clone()方法。
clone() 方法并不是Cloneable接口的方法,而是Object的一个protected方法。Cloneable接口只是规定,如果一个类没有实现Cloneable接口又调用了clone()方法,就会抛出CloneNotSupportedException。
2. 浅拷贝
拷贝对象和原始对象的引用类型引用同一个对象。
3. 深拷贝
拷贝对象和原始对象的引用类型引用不同对象。
4. clone的替代方案
可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象
六、关键字
final
1. 数据
声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。
对于基本类型,final使数值不变
对于引用类型,final使引用不变,也就不能引用其他对象,但是被引用的对象本身是可以修改的。
2. 方法
声明方法不能被子类重写。
private方法隐式地被指定为final,如果在子类中定义的方法和基类中的一个private方法签名相同,此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。
3. 类
声明类不允许被继承。
static
1. 静态变量
静态变量:类变量,属于类,类所有的实例都共享静态变量,可以直接通过类名来访问它。静态变量在内存中只存在一份。
实例变量:每创建一个实例就会产生一个实例变量,它与该实例同生共死。
2. 静态方法
静态方法:静态方法在类加载的时候就存在了,它不依赖于任何实例。所以静态方法必须有实现,不能是抽象方法。
只能访问所属类的静态字段和静态方法,方法中不能有this和super关键字。
3. 静态语句块
在类初始化时运行一次。
4. 静态内部类
非静态内部类依赖于外部类的实例,而静态内部类不需要。
静态内部类不能访问外部类的非静态的变量和方法。
5. 静态导包
使用静态变量和方法时不需要指明ClassName,从而简化代码,但是可读性大大降低。
6. 初始化顺序
静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于他们在代码中的顺序。
七、 反射
每个类都有一个Class对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着Class对象。
类加载相当于Class对象的加载,类在第一次使用时才动态加载到JVM中,也可以使用 Class.forName("com.mysql.jdbc.Driver") 这种方式来控制类的加载, 该方法会返回一个Class对象。
反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的.class 不存在也可以加载进来。
八、 异常
Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: Error 和 Exception。其中 Error 用来表示 JVM 无法处理的错误,Exception 分为两种:
- 受检异常 :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
- 非受检异常 :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。
九、泛型
public class Box<T> // T stands for "Type" private T t; public void set(T t) this.t = t; public T get() return t;
十、注解
Java 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。
Java 与 C++ 的区别
- Java 是纯粹的面向对象语言,所有的对象都继承自 java.lang.Object,C++ 为了兼容 C 即支持面向对象也支持面向过程。
- Java 通过虚拟机从而实现跨平台特性,但是 C++ 依赖于特定的平台。
- Java 没有指针,它的引用可以理解为安全指针,而 C++ 具有和 C 一样的指针。
- Java 支持自动垃圾回收,而 C++ 需要手动回收。
- Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
- Java 不支持操作符重载,虽然可以对两个 String 对象执行加法运算,但是这是语言内置支持的操作,不属于操作符重载,而 C++ 可以。
- Java 的 goto 是保留字,但是不可用,C++ 可以使用 goto。
- Java 不支持条件编译,C++ 通过 #ifdef #ifndef 等预处理命令从而实现条件编译。
以上是关于Java 基础的主要内容,如果未能解决你的问题,请参考以下文章