包
包的定义
包 (package) 是组织类的一种方式。使用包的主要目的是保证类的唯一性。
例如,你在代码中写了一个 Test 类, 然后你的同事也可能写一个 Test 类, 如果出现两个同名的类, 就会冲突, 导致代码不能编译通过。
包的访问权限控制
我们已经了解了类中的 public 和 private。private 中的成员只能被类的内部使用。如果某个成员不包含 public 和 private 关键字, 此时这个成员可以在包内部的其他类使用, 但是不能在包外部的类使用。
static关键字
static的用途:
- 修饰属性
- 修饰方法
- 代码块
- 修饰类
如果类中的某个成员被static修饰了,就说明这个成员是一个类属性/类方法。如果没有被static修饰,就说明这个成员是一个实例属性/实例方法。静态方法不需要创建实例,就可以直接使用。
结合代码具体说明:
a) 修饰属性
Java静态属性和类相关, 和具体的实例无关。换句话说, 同一个类的不同实例共用同一个静态属性。
class TestDemo{
public int a;
public static int count; }
public class Main{
public static void main(String[] args) {
TestDemo t1 = new TestDemo();
t1.a++;
TestDemo.count++;
System.out.println(t1.a);
System.out.println(TestDemo.count);
System.out.println("============");
TestDemo t2 = new TestDemo();
t2.a++;
TestDemo.count++;
System.out.println(t2.a);
System.out.println(TestDemo.count);
}
}
运行结果:
b) 修饰方法
如果在任何方法上应用 static 关键字,此方法称为静态方法。
- 静态方法属于类,而不属于类的对象。
- 可以直接调用静态方法,而无需创建类的实例。
- 静态方法可以访问静态数据成员,并可以更改静态数据成员的值。
class TestDemo{
public int a;
public static int count;
public static void change() {
count = 100;
//a = 10; error 不可以访问非静态数据成员
}
}
public class Main{
public static void main(String[] args) {
TestDemo.change();//无需创建实例对象 就可以调用
System.out.println(TestDemo.count);
}
}
运行结果:
注意事项:
静态方法和实例无关, 而是和类相关. 因此这导致了两个情况:
- 静态方法不能直接使用非静态数据成员或调用非静态方法(非静态数据成员和方法都是和实例相关 的).
- this和super两个关键字不能在静态上下文中使用(this 是当前实例的引用, super是当前实例父类实 例的引用,也是和当前实例相关).
- 同理,也无法在static方法中访问非static的变量和方法。(代码中的a=10就是错误的)
c)修饰代码块(下面代码块涉及)
d)修饰类(下面内部类涉及)
代码块
定义:
使用 { } 定义的一段代码。根据代码块定义的位置以及关键字,又可分为以下四种:
- 普通代码块
- 构造块
- 静态块
- 同步代码块(涉及多线程)
a)普通代码块
public class Main{
public static void main(String[] args) {
{ //直接使用{}定义,普通方法块
int x = 10 ;
System.out.println("x1 = " +x);
}
int x = 100 ;
System.out.println("x2 = " +x);
}
}
运行结果:
b)构造代码块
构造代码块是定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。
class Person{
private String name;//实例成员变量
private int age;
private String sex;
public Person() {
System.out.println("执行构造代码块!");
}
//实例代码块
{
this.name = "sky";
this.age = 12;
this.sex = "man";
System.out.println("执行实例代码块!");
}
public void show(){
System.out.println("name: "+name+" age: "+age+" sex: "+sex);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.show();
}
}
运行结果:
注意: 实例代码块优先于构造函数执行。
c)静态代码块
static修饰代码块,该代码块只是在类加载的时候执行一次,往往用来初始化静态成员。
class Person{
private String name;//实例成员变量
private int age;
private String sex;
private static int count = 0;//静态成员变量 由类共享数据 方法区
public Person(){
System.out.println("I am Person init()!");
}
//实例代码块
{
this.name = "sky";
this.age = 12;
this.sex = "man";
System.out.println("I am instance init()!");
}
//静态代码块
static {
count = 10;//只能访问静态数据成员
System.out.println("I am static init()!");
}
public void show(){
System.out.println("name: "+name+" age: "+age+" sex: "+sex);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();//静态代码块是否还会被执行?
}
}
运行结果 :
注意事项:
- 静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
- 静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行。
内部类
在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:静态内部类、匿名内部类、成员内部类和局部内部类。
public class A{
}
class B{
}
像上面这样,类B定义在类A{ }花括号外部的,即使是在一个文件里,也不是内部类。
a)静态内部类
静态内部类的定义:
public class Test {
static class B{
}
public static void main(String[] args) {
B b1 = new Test.B();
//在当前类Test中使用时,和静态变量,静态方法类似,也可以把Test.B()省略写为B()
B b2 = new B();
}
}
静态内部类和静态变量、静态方法类似,静态内部类也是和当前类(Test)绑定。使用时,也是通过Test类来调用。
b)匿名内部类
匿名内部类的定义,是在一个方法或是代码块中定义的类,并且没有显示申明类的名称。正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写。但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口。
public class Test {
public static void main(String[] args) {
//定义了一个匿名内部类
A a = new A(){
};
}
}
class A{ }
匿名内部类是使用的非常多的一种内部类,和A a = new A(); 这样的实例操作不同,后边还有一个大括号,表示可以重写方法,其实是定义了另外一个类(没有显示的类名,所以叫匿名)。经常用在需要实例化某个对象,但需要重写方法时,比如new接口,抽象类就是使用匿名内部类较多的方式。