Java基础知识回顾(二)

类和对象,装箱与拆箱,修饰符与访问控制权限。

一、类:

主观抽象,是对象的模板,可以实例化对象。

习惯上类的定义格式:
package xxx;
import xxx;
public class Xxx{
属性…;

构造器…;

方法…;
}

二、访问控制权限

Java提供了public ,private,protected三个访问权限修饰词,提供了以下四种访问权限控制:

1、包访问权限;
2、public访问权限;
3、Private访问权限;
4、Protected访问权限;

包访问权限

包访问权限是Java为了便于程序员开发而给定的一种权限选择。当方法或域给定访问权限限制符时,其默认具有该权限。具有该权限的方法和域成员,在包内是完全可见的,而包外不可见。
对java文件中的类也是如此,若未指定限制符,其默认为包访问权限,只能在包内被使用,包外无法利用其生成对象。
当决定一个类对包外可见的时候,除了要将类的访问限定符改为public以外,自定义的构造器限定符也必须修改为public,不然将导致外部不可见。这类似于C++中友元类,友元类彼此可见以简化访问。Java中无显示的friendly关键字

public访问权限

当在方法或域前面显式的给定public限定符的时候其具有该权限控制。public权限是最为宽松的一种权限控制,对包的内部、外部都是完全可见的。
一个Java文件中最多只允许出现一个public类,当一个Java文件中无一个public类时,表明其仅供包内使用,对外界不可见!

类只有包访问权限和public访问权限两种

private访问权限

private是访问限定最为严格的一种权限。当方法或域为private权限时,表明其只针对该类的内部可见,类的外部是不可见的。

protected访问权限

protected权限是一种严格程度介于public和private之间的权限,具有protected权限的域和方法只能对其自身和导入(import)该类的类可见。

在面向对象的设计当中最常见的是public和private访问权限两种。一般情况下将域定义为private,将方法定义为public。外界使用该类时,通过public方法使用其接口,而具体的域成员则对外部屏蔽,只能通过类提供的接口间接访问。

作用域 当前类 同一package 子类 其他package
public
protected x
friendly x x
private x x x

三、Java修饰符

static修饰符

static修饰符吧对象相关的(属性、方法等)变成类相关的,它可以修饰属性、方法、代码块和内部类。

static修饰属性(类变量)

那么这个属性就可以使用“类名.属性名”来访问,也就是使这个属性成为本类的类变量,为本类对象所共享。
这里提及下类加载的过程:类本身也是保存在文件中(字节码文件保存着类的信息),Java会通过I/O流把类的文件读入JVM,这个过程成为类的加载。JVM会通过类路径(CLASSPATH)来找字节码文件。需要的时候才会进行类加载,生成对象时是先加载后构造。
static修饰的类变量会在加载时自动初始化,初始化规则和实例变量相同。
类中的实例变量是在创建对象时被初始化的。
static修饰的属性是在类加载时被创建并进行初始化,类加载的过程只进行一次,也就是类变量只会被创建一次。

static修饰方法(静态方法)

static修饰的方法会成为整个类所共有的方法,可以用类名.方法名访问。
static修饰的方法不能直接访问本类中的非静态成员,但本类中的非静态方法可以访问本类的静态成员。
在静态方法中不能使用this关键字。
父类中是静态方法,子类不能覆盖为非静态方法;在符合覆盖规则的前提下,在父子类中,父类中的静态方法可以被子类中静态方法覆盖,但是没有多态(因为在使用对象调用静态方法时其实是调用的编译时类型的静态方法)。
Java中main方法必须写成static的原因:在类加载时无法创建对象,而静态方法可以不通过对象调用,所以在类加载时就可以通过main方法入口来运行程序。

static修饰初始化代码块(静态初始代码块)

static修饰的初始化代码块只在类加载时被执行一次。可以用静态初始化代码块初始化一个类。
下面例子现实的类中有static方法,static变量和static初始化块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UseStatic {
static int a = 2; //static修饰属性
static int b;
static void meth(int x) //static修饰方法
{
System.out.println("x=" + x);
System.out.println("a=" + a);
System.out.println("b=" + b);
}
static { //static修饰初始代码块
System.out.println("Static block initalized");
b = a * 4;
}
public static void main(String[] args) {
meth(32);
}
}

输出结果:

1
2
3
4
Static block initalized
x=32
a=2
b=8

在定它们的类的外面,static方法和变量能独立于任何对象而被使用,只需要在类的名字后面加点号运算符即可。形如:classname.method。一个static变量可以用同样的格式来访问,这就是Java如何实现全局功能和全局变量的一个控制版本。我在公司实际项目中就有个Global.java全局静态数据类用来存放全局静态变量。

简明来说就是,static成员不能被其所在class创建的示例访问。
总结:如果不加static修饰的成员是对象成员,也就是归每个对象多有;
加static修饰的成员是类成员,可以有一个类直接调用,为所有对象共有。

final修饰符

可以修饰变量、方法、类

final修饰变量

被final修饰的变量就会变成常量,一旦赋值不能改变。
静态常量(static final)只能在初始化时直接赋值。

final修饰方法

被final修饰的方法将不能被其子类覆盖,保持方法的稳定不被覆盖。

final修饰类

被final修饰的类将不能被继承。
注意:
final不能用来修饰构造方法。
问:使用final关键字修饰一个变量时,是引用不能变还是引用的对象不能变?
下面让我们来看这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class TestFinal {  
public static void main(String[] args) {
final StringBuilder sb = new StringBuilder("haha");
//同一对象的hashCode值相同
System.out.println("sb中的内容是:"+sb);
System.out.println(sb+"的哈希编码是:"+sb.hashCode());
sb.append("我变了");
System.out.println("sb中的内容是:"+sb);
System.out.println(sb+"的哈希编码是:"+sb.hashCode());
System.out.println("-----------------哈希值-------------------");
TestFinal test = new TestFinal();
System.out.println(test.hashCode());
System.out.println(Integer.toHexString(test.hashCode()));
System.out.println(test.getClass()+"@"+Integer.toHexString(test.hashCode()));
System.out.println(test.getClass().getName()+"@"+Integer.toHexString(test.hashCode()));
//在API中这么定义toString()等同于 getClass().getName() + '@' + Integer.toHexString(hashCode())
//返回值是 a string representation of the object.
System.out.println(test.toString());
}
}

代码结果是:

1
2
3
4
5
6
7
8
9
10
sb中的内容是:haha
haha的哈希编码是:1928052572
sb中的内容是:haha我变了
haha我变了的哈希编码是:1928052572
-----------------哈希值-------------------
1398828021
53606bf5
class TestFinal@53606bf5
TestFinal@53606bf5
TestFinal@53606bf5

可以看出StringBuilder中的内容变了 而所指向的哈希编码却没发生变化,在Java中每一个对象都有自己独一无二的哈希编码,根据这个编码就可以找到相关的对象,也就是说,根据这个编码你可以独一无二地确定这个对象。
因而使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。
总得来说对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

final,finally,finalize的区别:
final:用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义为final类型。
finally:是异常处理语句结构的一部分,是异常的统一出口,表示总会执行。
finalize:是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM不保证此方法总被调用。

abstract修饰符

abstract表示抽象的,可以修饰类和方法,分别叫做抽象方法和抽象类。人们在认识事物的时候,会把具有相同特征和行为的事务归为一个抽象类。比如动物就是一个很抽象的概念。当得到动物的实例时总是指某个具体物种的实例。所以说,在需要某个抽象类的实例时,只能够用某个具体类的实例来代替。抽象类不能实例化,不能生成抽象类的对象,但能定义一个引用。

abstract修饰类:

abstract修饰的类会使这个类成为一个抽象类,这个类将不能生成对象实例,但可以作为对象变量声明的类型,也就是编译时类型。
抽象类就是相当于一个类的半成品,需要子类继承并覆盖其中的抽象方法,这时子类才有创造实例的能力,如果子类没有实现父类的抽象方法,那么子类也要为抽象类。

abstract修饰方法:

abstract修饰的方法会使这个方法称为抽象方法,也就是只有声明而没有实现,没有方法体。抽象方法代表了某种标准,定义标准,定义功能,在子类中去实现。如果方法一时间想不到怎么被实现,或者有意要子类去实现而定义某种标准,这个方法可以被定义为抽象的。

注意:
1.有抽象方法的类一定是抽象类,但是抽象类中不一定都是抽象方法,也可以有部分全是具体方法。
2.当一个非抽象类继承自某个抽象类时,必须实现所继承抽象类的所有抽象方法,即抽象类的第一个非抽象子类必须要实现其父类所有的抽象方法,其中也包括父类继承的抽象方法
3.一个类中只要包含抽象方法,那么这个类就必须被定义为抽象类,反之,即使一个类不包含任何抽象方法,这个类仍然可以被定义为抽象类。
4.abstract和final不能同时使用,这两个关键字有着相反的含义。private和abstract也不能同时修饰方法,因为private阻止继承,也就阻止了重写实现,与abstract的意义相违背。