一、变量定义以及其存储与访问
1.变量总类
根据Java中定义变量位置的不同,变量有两大类:成员变量和局部变量,而成员变量里面根据有无static修饰又可分为类变量和实例变量
2.各变量定义
(1)成员变量:类中定义的变量(方法之外),用来描述对象的属性特征。
(2)局部变量:在类的方法中方定义的变量,用来保存临时数据。
(3)类变量:成员变量中,被static修饰符修饰的变量称为类变量,也叫静态变量
(4)实例变量:成员变量中,不被static修饰符稀修饰的变量称为实例变量
3.各变量区别
类变量 | 实例变量 | 局部变量 | |
---|---|---|---|
定义位置 | 在类中,方法外 | 在类中,方法外 | 方法中,或者方法形式的参数 |
初始化值 | 有默认初始化值 | 有默认初始化值 | 无定义,赋值后才能使用 |
调用方式 | 对象调用,类名直接调用 | 对象调用 | / |
存储位置 | 方法区 | 堆中 | 栈中 |
生命周期 | 与类共存亡 | 与对象共存亡 | 与方法共存亡 |
别名 | 静态变量 | / | / |
解释:
- 堆:此内存区域的唯一目的就是存放实例对象,几乎所有的实例对象都在这里分配内存(所有对象实例以及数组都要在堆上分配)
- 栈:虚拟机栈,用于存放局部变量表,局部变量表存放了编译期可知长度的各种8大基本数据类型、对象引用(reference类型,它不同于对象本身,是对象在堆内存的首地址)。方法执行完,自动释放
- 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据
4.各变量注意点
- 同一方法中不允许局部变量同名,不同方法中可以有同名的局部变量
- 局部变量必须要有最初始值,成员变量可没有,后面方法里面有赋值也可行
- 成员变量和局部变量同名时,局部变量有更高优先级
- 类变量独立于该类的任何对象,被类的所有实例共享,即JVM只为类变量分配一次内存,在加载类的过程中即完成类变量的内存分配,可用类名或对象名直接访问:
类名.类变量名
实例名.类变量名
- 实例变量可以在内存中有多个拷贝,即每创建一次实例,就会为实例变量分配一次内存,通过对象访问 :
实例名.实例变量名
举个例子说明三种变量
class Text {
static int a;//类变量(静态变量)
int b;//实例变量
}
public class TextForVariable {
public static void main(String[] args) {
int a = 10;//局部变量
int b = 11;//局部变量
a=12;
b=13;
Text.a = 1;
Text text = new Text();
text.a = 2;
text.b = 2;
Text text1 = new Text();
text1.a = 3;
text1.b = 3;
System.out.println(a);
System.out.println(b);
System.out.println(Text.a);
System.out.println(Text.a);
System.out.println(text.a);
System.out.println(text1.a);
System.out.println(text.b);
System.out.println(text1.b);
}
}
输出的结果为:
12
13
3
3
3
3
2
3
可以看到,所有的类变量的值都为最后一次的赋值3;而实例变量可以多次赋值;局部变量也只能有一次最终的赋值。
二、代码块
- 基本上代码块分为三种:static静态代码块、构造代码块、普通代码块
- 代码块执行顺序为静态代码块>构造代码块>构造函数>普通代码块
- 继承中代码块的执行顺序:父类静态块>子类静态块>父类代码块>父类构造器>子类代码块>子类构造器
1.静态代码块
(1)定义
static代码块也叫静态代码块,是在类中独立于类成员的static代码块
- 使用格式:
static{
}
- 几个小点
1、static代码块只执行一次
2、静态块常用来执行类属性的初始化
3、静态块优先于各种代码块以及构造函数,一个类中可以有多个静态代码块,则按照书写顺序执行
4、静态代码快要独立于类成员,可以定义在类中的任何地方除了方法体中
5、静态代码可通过对象访问普通变量
(2)举例
public class TestStatic {
private int b;
private static int a;
static {
TestStatic.a = 6;//此处可直接写成a=6
System.out.print(a + "\t");
TestStatic ts = new TestStatic();
ts.show();
ts.b=200;
System.out.print(ts.b+"\t");
}
public static void main(String[] args){}
static {
TestStatic.a=9;
System.out.print(a+"\t");
}
void show(){
System.out.print("abc"+"\t");
}
}
输出结果:
6 abc 200 9
(3)分析
只要含有static关键字的类被加载,Java虚拟机就能根据类名找到它们。因此,static对象可以在类的任何对象创建之前访问,无须引用任何对象。所以静态代码块的存在在类加载的时候就自动运行了,而普通方法和静态方法都不能自动运行,前者需要对象,后者需要加载类之后才能调用,故static代码块优先于所有方法之前执行。
三、this关键字
1.代表当前对象
当this出现在某个方法体中,它可以代表当前类的任何一个实例对象。Leaf类setColor方法中的this可以代表Leaf类中的任何一个对象,只有这个方法被调用时,它所代表的具体对象才能被确定下来,此时谁在调用这个方法,this就代表谁。
class Leaf {
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
public class TestThis {
public static void main(String[] args) {
Leaf f1 = new Leaf();
f1.setColor("红色");//此时setColor中的this代表的是f1这个实例
System.out.println("第一片叶子是:"+f1.getColor()+"的");
Leaf f2=new Leaf();
f2.setColor("黄色");//此时setColor中的this代表的是f2这个实例
System.out.println("第二片叶子是:"+f2.getColor()+"的");
}
}
同理,出现在构造方法中时也是一样的,例如:
class Student{
String name;
int age;
public Student(String name,int age){
this.name = name;
this.age = age;
}
}
public class TestThis {
public static void main(String[] args) {
Student s1 = new Student("李红",22);
Student s2 = new Student("王明",30);
}
}
(1)当局部变量和成员变量相同时,成员变量会被隐藏,如果此时需要使用成员变量,则必须通过this来引用成员变量
class Fruit {
String color = "绿色";
public void harvest() {
String color = "红色";
System.out.println("这种水果收割时是红色:" + color);//此时color是局部变量
System.out.println("原来是:" + this.color);//此时color是成员变量
}
}
public class TestFruit {
public static void main(String[] args) {
Fruit fruit = new Fruit();
fruit.harvest();
}
}
(2)通过this调用成员方法
void sing(){
System.out.println("我会唱歌");
}
void dance(){
this.sing();//可直接写成sing(),非静态调非静态时可直接调用
System.out.println("我也会跳舞");
}
2.调用当前类的其它构造方法
语法格式:
this([参数])
class People{
String name;
int age;
People(String name){
this.name=name;
}
People(String name,int age){
this(name);//调用了该类的带一个参数的构造方法
this.age=ge
}
四、类成员与实例成员的使用规则
如果使用static修饰某个方法,这个方法就成为静态方法或类方法,通过类名可直接访问。没有static方法修饰的是实例方法,需要通过对象对其访问。那么,如果一个类的成员变量和方法前都有static修饰,就统称该成员为类成员或静态成员,否则称为实例成员。
1.使用规则
- 类方法可以直接引用类变量,但不能直接引用非静态变量
- 类方法中使用非静态变量,要先创建类的对象,再通过对象访问非静态变量
- 实例方法中,可以直接访问同类的非静态和静态变量
- 静态方法中,不能使用this关键字, this是相对于某个对象而言的,static修饰的方法是相对于类的,因此不能在静态方法中用this
2.举例
public class TextStatic {
static String a = "abc";
String b = "java";
void printValue() {
System.out.println(a);
System.out.println(b); //正确,实例方法中能直接调用非静态变量和静态变量
this.b="2";//正确,非静态方法中可以使用this调用非静态方法;
}
public static void main(String[] args) {
System.out.println(a);//静态方法中可直接访问静态变量
// System.out.println(b); //错误,静态方法中不能直接调用非静态变量
TextStatic textStatic = new TextStatic();
System.out.println(textStatic.b);//静态方法中需要实例化对象才能访问非静态变量
textStatic.printValue();//静态方法中调用非静态方法也需要实例化对象
this.b="2";//错误,静态方法中不能使用this
}
}
五、final修饰变量
- final有不可改变,最终的意思,可以用来修饰非抽象类、成员方法和变量
- 抽象类要被引用,所以不能用final修饰
- final修饰的变量一旦被赋值就不可再改变,变量名称定义时一般用大写字母组成
1.final修饰成员变量
final修饰的成员变量只能被赋值一次,赋值后的其值不能再改变,一般通过两种方式指定最初始值。
(1) 被final修饰的变量在定义时,一般同时赋初值
final int FUNCTION = 7; //正确
final int FUNCTION;
FUNCTION=7;//错误
(2)被final修饰的成员变量,如果没有在定义的同时赋初值则必须在构造方法中赋值
public class ExampleDemo {
final float FUNCTION;//PI没有在定义的同时赋初值
ExampleDemo(){
FUNCTION=3.15f;//在构造方法中完成赋值
}
public static void main(String[] args){
ExampleDemo exampleDemo = new ExampleDemo();
System.out.println(exampleDemo.FUNCTION);
}
}
这种先定义再在构造方法中赋值 的方式在使用上提供了更大的灵活性,这样的final成员变量可以根据对象不同而有所不同,却又可以保持不变的特性
2.final修饰局部变量
final修饰的局部变量必须被显式的赋初值,可以在定义时赋初值,也可以在后面的代码中赋值,但只能赋值一次。
public class ExampleDemo {
public static void main(String[] args) {
ExampleDemo exampleDemo = new ExampleDemo();
exampleDemo.test();
}
public void test() {
final int a;//局部变量a,需要的时候赋值
final int b = 8;//局部变量b,定义的同时赋值
a = 5;//只能赋值一次
System.out.println(a);
System.out.println(b);
}
}
3.总结
final修饰的变量在使用之前必须被初始化,而且只能显式的赋值一次。
public class ExampleDemo {
private final String A="final";
private final int B=30;
public static final int C=26;
public final int E;
//一个对象一个新的常量值
public ExampleDemo(int x){
E=x;
}
public static void main(String[] args) {
ExampleDemo exampleDemo = new ExampleDemo(2);
exampleDemo.C=50;//错误,final变量不能再次赋值
System.out.println(exampleDemo.A);
System.out.println(exampleDemo.B);
System.out.println(ExampleDemo.C);
System.out.println(exampleDemo.E);
ExampleDemo exampleDemo1 = new ExampleDemo(3);
System.out.println(exampleDemo1.E);//变量E因为对象的不同而不同
exampleDemo1.test();
}
public void test() {
final int a;//局部变量a,需要的时候赋值
final int b = 8;//局部变量b,定义的同时赋值
a = 5;//只能赋值一次
System.out.println(a);
System.out.println(b);
}
}