Mind Map
1. 属性
1.1 实例变量
实例变量也叫成员变量, 为了封装性, 一般加 private
修饰符以阻止外部直接访问,当然还有 static
静态变量(类变量)和 final
常量等。
成员变量可以进行显式赋值,也可以不这样做。
成员变量在类加载阶段会首先将字节全刷为 0
,对应于 int
的 0
,char
的 '\u0000'
,long
的 0l
,float
的 0f
,double
的 .0
,boolean
的 false
,以及引用数据类型的 null
。之后再刷入显式赋值的值。之后再调用构造函数。
private char ch;
public static int count = 0;
public static final double PI = 3.141592653;
1.2 类变量
类的成员中, static
修饰的类的变量为静态变量, 或类变量. 类变量由该类的所有实例共享, 不用创建对象就可以被访问.
2. 代码块
2.1. 构造代码块
构造代码块的出现本质是为了提取构造函数的共同代码, 减少各个构造函数的代码而产生的.
**
public class Client {
{//构造代码块
System.out.println("执行构造代码块");
}
}
理解构造代码块:**
- 构造代码块的作用是给对象进行初始化.
- 对象一建立就运行构造代码块了,而且优先于构造函数执行。这里要强调一下,有对象建立,才会运行构造代码块,类不能调用构造代码块的,而且构造代码块与构造函数的执行顺序是前者先于后者执行。
- 构造代码块与构造函数的区别是:构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化,因为构造函数是可以多个的,运行哪个构造函数就会建立什么样的对象,但无论建立哪个对象,都会先执行相同的构造代码块。也就是说,构造代码块中定义的是不同对象共性的初始化内容。
注意:
- 可以有输出语句.
- 可以对类的属性, 类的声明进行初始化操作.
- 可以调用静态的变量或方法.
- 若有多个非静态的代码块, 那么按照从上到下的顺序依次执行.
- 每次创建对象的时候, 都会执行一次, 且先于构造器执行.
构造代码块是依托于构造函数, 也就是说在通过 new
关键字生成一个实例的时候, 相当于把代码块加到构造器最前面, 会先执行构造代码块, 然后再执行其他代码.
而我们知道任何构造器, 如果里面有 this(...)
, 这个时候编译器会足够聪明, 不再给其前面添加构造区代码块, 而是跳转到 this(...)
直到构造器中没有 this()
, 这个时再添加构造代码块.
而当有继承关系时, 如果有 super(...)
则直接跳转到父类构造器, 如果是 this(...)
同样先跳转到没有 this(...)
的构造器, 这个时候构造器首行默认添加 super()
, 从此入口跳转到父类的构造器, 同样先执行父类的构造代码块, 执行完之后再执行父类构造器, 再回来, 接着才执行子类的构造代码块, 最后执行子类构造器. 这一部分可参见对象的创建过程.
2.2. 静态代码块
静态代码块的出现本质是为了给类初始化的. 用 staitc 声明, jvm 加载类时执行, 仅执行一次.
**
class A{
static{//静态代码块
}
}
理解静态代码块:
- 它是随着类的加载而执行,只执行一次,并优先于主函数。具体说,静态代码块是由类调用的。类调用时,先执行静态代码块,然后才执行主函数的。
- 静态代码块其实就是给类初始化的,而构造代码块是给对象初始化的。
- 静态代码块中的变量是局部变量,与普通函数中的局部变量性质没有区别。
- 一个类中可以有多个静态代码块.
静态代码块在类加载时执行, 同样注意:
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
- 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
- 静态代码块的执行要先于非静态代码块。
- 静态代码块只执行一次
以下例子:
public class Test{
staitc int cnt=6;
static{
cnt+=9;
}
public static void main(String[] args) {
System.out.println(cnt);
}
static{
cnt/=3;
}
}
运行结果:
5
3. 构造器
类还包含方法,在之前部分介绍过,方法也可以通过修饰符修饰。类中还有特殊的方法——构造方法,或构造器(constructor)。
构造器本质是一个方法,但是有其特殊性:
- 方法名和类名一致,唯一允许首字母大写的方法名;
- 没有返回值声明,甚至连
void
也不允许; - 不能被关键字
static
,final
,synchronize
,native
,abstract
等修饰 ; - 不能像普通方法一样随意调用,只能调用一次。某个对象的生命周期中只能调用一次。
需要注意的是:
- Java语言中,每个类都至少有一个构造器。
- 默认构造器的修饰符与所属类的修饰符一致。
- 一旦显式定义了构造器,则系统不再提供默认构造器。
- 一个类可以创建多个重载的构造器,一般我们需要提供空参构造器和全参构造器。
- 父类的构造器不可被子类继承。
构造器重载,还可以连环调用,但是一定要保证有一个构造器中是没有 this(…)
,防止无限递归。
举例:以下空参构造出 name = "Amos", age = 24
的 Person
对象,而也可以通过 new Person(Cathy, 23);
来创建对象。
public class Person{
private String name;
private int age;
public Person(){
this("Amos", 24);
}
public Person(String name, int age){
this.name = name;
this.age = age;
}
4. 静态方法
没有对象的实例时, 可以用 ClassName.method()
的形式访问由 static 标记的类方法.
需要注意的是:
- 在 static 方法内部只能访问类的 static 属性和方法, 不能访问类的非 static 属性和方法.
- 因为不需要实例就可以访问 static 方法, 因此 static 方法内部不能有
this
, 也不能有super
. - 重载的方法需要同时为 static 的或者非 static 的.
5. 内部类
在Java中, 允许一个类的定义位于另一个类的内部, 前者称为内部类(inner class), 后者称为外部类.
注意:
- 内部类一般用在定义它的类或语句块之内, 在外部引用它时必须给出完整的名称;
- 内部类的名字不能与包含它的类名相同;
内部类可以使用外部类的私有数据,因为它是外部类的成员,同一个类的成员之间可相互访问. 而外部类要访问内部类中的成员需要:
内部类.成员
或者内部类对象.成员
.5.1. 成员内部类
成员内部类, 隶属于外部类对象的. 在内部类中可以随意访问外部类成员:
class Outer { // 顶级类只能被public和default修饰 private int num = 10; // 和对象关联类似, 但是比对象关联好用, 因为可以访问私有成员. 对象关联只能使用关联对象的公共成员. class Inner1 { // 支持所有访问权限修饰符 // 成员内部类不允许声明静态属性. private int num = 100; public int getNum() { return num; } public void inner1Test1() { // this可以加类限定, 更清晰明确 System.out.println("成员内部类的属性 : " + Inner1.this.num); // 100 System.out.println("成员内部类访问外部类属性 : " + Outer.this.num); // 10 outerTest2(); // 可以访问私有方法 } } public void outerTest1() { System.out.println("外部类方法"); // 如果想要调用内部类方法 Inner1 inner1 = this.new Inner1(); // 通过当前类对象new一个内部类对象 inner1.inner1Test1(); System.out.println(this.num); // 10 System.out.println(inner1.num); // 100 } private void outerTest2() { System.out.println("私有方法"); } // 嵌套类, 加static修饰, 本质上和外部类是平级的 // static仅仅表示它和外部类的关系 public static class Inner2 { public static String name; // 可以定义静态变量 private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } } }
5.2. 局部内部类
5.2.1 普通局部内部类
普通局部内部类, 类的定义写在方法中, 不可以加访问控制修饰:
public class InnerClass{
public static void main(String[] args) {
// 普通局部内部类
final class Inner3 {
private int id;
@Override
public String toString() {
return "Inner3{" +
"id=" + id +
'}';
}
};
Inner3 inner3 = new Inner3();
inner3.id = 200;
System.out.println(inner3);
}
}
5.2.2 匿名内部类
匿名内部类, 没有类名, 不能后期创建对象, 在声明的同时必须马上创建唯一对象.
匿名内部类通常就是和接口配合(或实现父类), 接口中的方法通常也不多, 格式如下:
new 父类|接口() {
类体部分, 类体相当于new后面的父类或接口的实现子类.
};
举例如下:
interface MyInterface {
String getInfo();
}
interface MyInterface2 {
void test();
}
public class InnerTest {
@Test
public void anonymousInnerClassTest1() {
// 什么情况下使用匿名内部类? 临时的想要用某个接口的对象.而且对象也是一次性使用
// class Xxx implements MyInterface{};
// MyInterface mi = new Xxx(); 相当于以上两个语句合体.
new MyInterface2() {// 因为没有类名, 所以必须多态.
@Override
public void test() {
System.out.println("匿名内部类的test");
}
}.test(); // 匿名内部类的匿名对象, 一次性使用
// 这里看上去是 new Object 对象, 实际上是创建了一个直接子类, 可以在子类中重写或添加新的方法.
Object o = new Object() { // 匿名内部类是Object的直接子类
public String toString() {
return "我是匿名内部类对象";
}
};
System.out.println(o);
}
}
5. JavaBean
JavaBean 是一种Java语言写成的可重用组件, 是指符合如下标准的 java 类 :
- 类是公共的
- 有一个无参的公共的构造器
- 有属性,且有对应的get、set方法
用户可以使用 JavaBean 将功能、处理、值、数据库访问和其他任何可以用 java 代码创造的对象进行打包,并且其他的开发者可以通过内部的 JSP 页面、Servlet、其他 JavaBean、applet 程序或者应用来使用这些对象。用户可以认为 JavaBean 提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。