一.静态变量跟实例变量的区别:
- 静态变量:由static修饰,在JVM中,静态变量的加载顺序在对象之前,因此静态变量不依附于对象存在,可以在不实例化类的情况下直接使用静态变量,如下代码所示:
public class StaticTest {
static int a = 13; //静态变量
int b = 14; //非静态变量
public static void main(String[] args) {
int c = StaticTest.a;
System.out.println(c);
}
}
总结:静态变量属于类,不属于类中任何一个对象,因此静态变量又叫做类变量,一个类不管创建多少个对象(对象是类的一个实例),静态变量在内存中有且仅有一个。
2. 实例变量(非静态变量):必须依附于对象存在,只有实例化类后才可以使用此类中的实例变量,如下代码所示:
public class StaticTest {
static int a = 13;
int b = 14;
public static void main(String[] args) {
int d = new StaticTest().b;
System.out.println(d);
}
}
二.3种方法详解:
1.构造方法:
构造方法负责对象的初始化工作,为实例变量赋予合适的初始值。必须满足以下的语法规则:
- 方法名与类名相同
- 不要返回类型(例如return、void等)
- 不能被static、final、native、abstract和synchronized修饰,不能被子类继承
构造方法的作用域:(1)当前类的其他构造方法通过this语句调用;(2)当前类的子类的构造方法通过super语句调用;(3)在程序中通过new语句调用。
public class Sample{
private in x;
public Sample(){ //不带参数的构造方法
this(1);
}
public Sample(int x){ //带参数的构造方法
this.x=x;
}
public int Sample(int x){ //不是构造方法,return
return x++;
}
}
1.1 默认构造方法
默认构造方法时没有参数的构造方法,分为:
a.隐含的默认构造方法:public ClassName(){}; b.程序显示定义默认构造方法:public Employee(){this(“无名氏”);}
可以调用ClassName类的默认构造方法来创建对象,没有默认构造方法则不合法,例如:
ClassName c=new ClassName(); //此语句合法
1.2 重载构造方法
通过new创建一个对象后,在不同的条件下,对象可能会有不同的初始化行为,可以通过重载构造方法来表达对象的初始化行为。具体参考this关键字的用法。
1.3 子类调用父类的构造方法
父类的构造方法不能被子类调用,可以通过super语句调用父类的构造方法。例如:
public class MyExpection extends Exceptio{
public MyException(){
//调用Exception父类的Exception(String msg)方法
super("Something is error!");
}
public MyException(String msg){
//调用EXception父类的Exception(String msg)方法
super(msg);
}
}
1.4 子类调用父类的构造方法
用super调用父类的构造方法必须遵守以下规则:
a: 子类的构造方法中不能直接通过父类的方法名调用父类的构造方法,使用super语句;
b:加入在子类的构造方法中有super语句,它必须作为构造方法的第一条语句(同this语句);
1.5. 构造方法的private访问级别
构造方法为private级别时,意味着只能在当前类中访问它:当前类的其他构造方法中可以通过this语句调用,此外还可以在当前类的成员方法中使用new调用。
以下场合中,可以把类的所有构造方法声明为private:
a. 这个类中仅仅包含一些供其他程序调用的静态方法,没有任何实例方法。
b. 禁止这个类被继承。声明为private后,如果定义了它的子类,子类的方法中无法调用父类的任何构造方法。
c. 类需要把构造自身实例的细节封装起来,不允许其他程序通过new语句创建这个类的实例。提供静态方法。
2.静态方法:
方法用static关键字修饰,静态方法与静态成员变量一样,属于类本身,在类装载的时候被装载到内存,不自动进行销毁,会一直存在于内存中,直到JVM关闭。使用时也是不需要实例化类,能够直接使用。静态方法无法被重写。
public class StaticTest {
public static void MyStatic(){
System.out.println("这是StaticTest的一个静态方法");
}
public static void main(String[] args) {
StaticTest.MyStatic();
}
}
需要注意的是:在静态方法中只能访问类中的静态成员跟静态方法,不能直接访问类中的实例变量跟实例方法,原因是静态方法在JVM中的加载顺序也在对象之前,直接使用实例变量跟实例方法的话,可能实例变量跟实例方法所依附的对象并没有被创建,会导致无法找到所使用的实例变量跟实例方法。
要想使用实例变量跟实例方法可以采用如下方法:在静态方法中创建实例变量和实例方法所在的对象,通过这个对象来使用实例变量跟实例方法。如代码所示:
public class StaticTest {
int b = 14;
public void MyMethod(){
System.out.println("这是StaticTest的一个实例方法");
}
public static void MyStatic(){
StaticTest st = new StaticTest();
int e = st.b;
st.MyMethod();
}
}
3.实例化方法:
属于实例对象,实例化后才会分配内存,必须通过类的实例来引用。不会常驻内存,当实例对象被JVM 回收之后,也跟着消失,代码如下:
public class StaticTest {
public void MyMethod(){
System.out.println("这是StaticTest的一个实例方法");
}
public static void main(String[] args) {
new StaticTest().MyMethod();
}
}
三.总结:
- 线程安全: 静态方法是共享代码段,静态变量是共享数据段。既然是“共享”就有并发的问题。非静态方法是针对确定的一个对象的,所以不会存在线程安全的问题。
- 如果静态方法在系统中定义太多,会占用大量的资源,最后造成内存溢出,所以静态方法不能滥用。
- static修饰的静态方法会随着类的定义而被分配和装载入内存中,编译器只为整个类创建了一个静态变量的副本,也就是只分配一个内存空间,虽然可能有多个实例,但这些实例共享该内存,特别值得注意的是,任何一个对象对静态数据成员的修改,都会影响其它对象。
- 静态不能引用非静态这一特性,是由于静态的会随着类的定义而被分配和装载入内存中这一关键点决定的;如果静态引用了非静态的,根本无法从内存中找到非静态的代码段,势必会出错,这种做法是Java虚拟机决不允许的。
借鉴于:
1.https://blog.csdn.net/HaydenYu/article/details/73457278
2.https://blog.csdn.net/qq_28511781/article/details/71405945
3.https://www.cnblogs.com/zterry/p/6835417.html