标签:
1,JVM,JRE,JDK各是什么含义?之间的关系?
解答:
JVM:指java虚拟机,顾名思义就是模拟出来的东西。它的实现具体有,指令集、寄存器、组件文件格式、 栈、垃圾收集、堆内存区。可以把它理解为专门用来执行java程序的机器,也就是说JVM提供了java 执行硬件平台。JVM执行的代码都是以.class为后缀的字节码文件。
JRE:指java运行的环境。就像在电脑上运行一个软件的时候必须在windows或其他操作系统一样。可以 把JRE看成一个操作系统。也就是说JRE提供了java执行的软件平台。在运行java的工程中除了需 要有JVM执行代码外,还需javaAPI(应用编程接口,也就“类库”),所以JRE包括JVM。
JDK:开发java程序的环境。包括JRE和其他工具。
2,Java程序的工作方式?java虚拟机的工作原理?
Java程序工作方式:java源程序—>【编译】—>.class二进制字节码文件—>【解释执行】—> JVM执行。
JVM工作原理和特点: 是指操作系统装入JVM是通过jdk中Java.exe来完成,通过下面4步完成JVM环境.
a,创建JVM装载环境和配置。
b,装载JVM.dll。
c,初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例。
d,调用JNIEnv实例装载并处理class类。
3,java1.1事件处理机制
a, 事件是通过监听来实现,你希望在构件事件由哪个监听器处理,就将该监听器注册到该构件上。 JDK1.1事件处理模型中的监听器都是通过实现在包java.awt.event中提供的监听器接口来获得的。 每一种事件都有对应的监听器接口,事件处理方法都已经在该接口中定义了。
【 相关资料: JVM工作原理分析.pdf 】
Java 的原始数据类型共有8种,详如下:
1.基本的整数类型 |
2.浮点类型 |
||||||||||||||||||||||||||||||||||||||||
|
|
3.Char 类型
JAVA 中的一个字符,占2个字节16位,表示UNICODE 字符集中一个元素。
4.Boolean 类型
1个字节8位,两个有效值 true false。
注意:
1,一个字节为8位。
2,一个float 类型的值,必须以f(或F)作为后缀,否则会被当做double类型,对于double值来说, d(或D)后缀是可选的。
3,java中涉及到byte, short和char类型的运算,首先会把这些值转为int类型,然后对int类型 进行运算,如果高位要转为低位类型,需要用强制转换。
默认初始化
类型 |
byte |
short |
int |
double |
float |
long |
char |
boolean |
默认值 |
0 |
0 |
0 |
0.0 |
0.0 |
0 |
/u0000 |
false |
包装类 |
Byte |
Short |
Integer |
Double |
Float |
Long |
Character |
Boolean |
默认值 |
null |
null |
null |
null |
null |
null |
null |
null |
深入理解基本数据类型
1. Java字面值整数默认为int类型,小数默认为double类型。带L或l后缀的整数都是long类型,带F或f后缀的整数或小数都是float类型,带D或d后缀的整数或小数都是double类型。
2. int型的值可以赋给所有数据类型的变量,long型的值可以赋给long、float和double类型的变量,float型的值可以赋给float和double类型的变量,double型的值只能赋给double类型的变量。
3. int型的值在赋给byte和short类型变量的时候需要注意变量类型的取值范围,否则会出现编译错误。
4. 如果将一个大范围或高精度的数字类型转换为一个小范围或低精度的数字类型的时候,可以使用强制类型转换,但是会出现精度损失现象。
5. 运算符对基本数据类型的影响:
A, 当使用+、-、*、/、%进行基本数据类型运算的时候,只要两个操作数中有一个是高类型,另一个 也会被转换为高类型,并且结果也是高类型。数据类型的顺序由高到低依次为:double > float > long > int 。另外,所有byte、short和char类型的操作数都全部会被自动转换为int类型。
B,当使用+=、-=、*=、/=、%=进行基本数据类型运算的时候,运算符右边的数值将首先被强制转换成 与运算符左边数值相同的类型,然后再执行运算,且运算结果与运算符左边数值类型相同。
数组定义、初始化 使用未初始化的数组会产生何种异常(空指针异常的产生)
1, 内存中的数组
数组在内存中存放在两个地方:一个是栈(存放数组引用),一个是堆(存放数组元素).数组引用变 量可以指向任何有效内存,只有当该引用指向有效内存后,才可通过该数组变量来访问数组元素。
2, 基本类型数组和引用类型数组的初始化
简言之,基本类型数组在没有显示初始化时,默认值为该类型的默认值,数组中的元素存放在堆 上面,如果是引用类型数组,在没有显示初始化时,默认值为null,如果被显示初始化,这个数组中的元素是引用,而不是存放在堆上的元素。它指向另一块内存,这块内存里存储了有效数据。
例子 |
在堆上是否分配空间 |
初始值 |
int[] i; |
无(因为i为null) |
无 |
Person p[]; |
无(因为i为null) |
无 |
int[] i = new int[3]; |
有 |
0(基本类型的默认值) |
Person p[] = new Person[3]; |
有 |
null(对象的默认值) |
1, String类是final的,不可被继承.public final class String.
2, String类是的本质是字符数组char[], 并且其值不可改变.private final char value[].
3, 创建字符串的方式很多,归纳起来有三类:
方法1,直接指定.比如String s1 = "11";
方法2,使用new关键字创建字符串,比如String s1 = String s2 = new String("11")
方法3,使用串联生成新的字符串.比如String s3 = "1" + "1";
4, 创建方式的分析
方法1中:会在栈中创建一个对象引用变量str,然后查看栈中是否存在“11”,如果没有,则将“11” 存放进栈,并令引用变量str指向它;如果已经有“11”,则直接令str指向它;
方法2中:是java中标准的对象创建方式;首先会看字符串池中是否有"11",如果没有则创建;然 后,其创建的对象将直接放置到堆中,每调用一次就会创建一个新的对象。
String s3 = "abc"; String s31 = "a" + "bc"; String s32 = new String(s31); System.out.println(s32.toString()); // abc System.out.println(s3 == s31); // true System.out.println(s31 == s32); // false |
方法3中:先在内存中查找是否有"1",没有则创建,然后再通过+方式创建的"11"看看是否在字符串 池中存在该对象,如果存在,则返回该对象引用。
5, String类是一个不变模式的应用。常量池是包括字符串池的。
String对象的创建也很讲究,关键是要明白其原理.
原理1: 当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个X在String 池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加.
原理2:Java中,只要使用new关键字来创建对象,则一定会(在堆栈区)创建一个新的对象.
原理3:使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字 符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象.但是如果连接的不是纯字符串,那么会创建新的字符串在堆上。
原理4:使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区 创建一个String对象.
另外,String的intern()方法是一个本地方法,定义为public native String intern(); intern()方法的价值在于让开发者能将注意力集中到String池上.当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串.否则,将此 String 对象添加到池中,并且返回此 String 对象的引用.
最后,有几点问题请大家注意:String a; 与String a=null在作为类变量时候是等价的,在局部变量则不同.null表示一个空引用,String a=null意思是在栈中声明了a,但是这个a没有指向任何地址.此时我们注意到String a 在栈中声明了a,但是也没有指向任何地址,但是java的语法检查如果在局部变量中,String a;是不能直接使用的,String a=null中的这个a可以直接使用.
String s3 = "abc"; String s30 = "bc"; String s31 = "a" + s30; String s32 = "a" + new String("bc"); String s33 = "a" + "bc"; System.out.println(s3 == s31); // false System.out.println(s3 == s32); // false System.out.println(s3 == s33); // true // 该例子验证了原理3和原理4. |
1,"abc"与new String("abc");
String s = new String("abc");创建了几个String Object?(如这里创建了多少对象?)
这个问题比较简单,涉及的知识点包括:
a,引用变量与对象的区别; b, 字符串"abc"是一个String对象; c, 字符串池和堆[heap]中的字符串对象。字符串对象的创建:由于字符串对象的大量使用[它是一个对象,一般而言对象总是在heap分配内存],Java中为了节省内存空间和运行时间[如比较字符串时,==比equals()快],在编译阶段就把所有的字符串文字放到一个字符串池中,而运行时字符串池成为常量池的一部分.字符串池的好处,就是该池中所有相同的字符串常量被合并,只占用一个空间.我们知道,对两个引用变量,使用==判断它们的值[引用]是否相等,即指向同一个对象。
现在看String s = new String("abc");语句,这里"abc"本身就是pool中的一个对象,而在运行时执行new String()时,将pool中的对象复制一份放到heap中,并且把heap中的这个对象的引用交给s持有.ok,这条语句就创建了2个String对象.
String s1 = new String("abc") ;
String s2 = new String("abc") ;
if( s1 == s2 ){ //不会执行的语句}
这时用==判断就可知,虽然两个对象的"内容"相同[equals()判断],但两个引用变量所持有的引用不同,
上面的代码创建了几个String Object? [三个,pool中一个,heap中2个.]
2,字符串的+运算和字符串转换
字符串转换和串接是很基础的内容,因此我以为这个问题简直就是送分题.事实上,我自己就答错了.
String str = new String("jf"); // jf是接分
str = 1+2+str+3+4;
一共创建了多少String的对象?[我开始的答案:5个.jf,new,3jf,3jf3,3jf34]
首先看JLS的有关论述:
一,字符串转换的环境[JLS 5.4 String Conversion]
字符串转换环境仅仅指使用双元的+运算符的情况,其中一个操作数是一个String对象.在这一特定情形下,另一操作数转换成String,表达式的结果是这两个String的串接.
二,串接运算符[JLS 15.18.1 String Concatenation Operator + ]
如果一个操作数/表达式是String类型,则另一个操作数在运行时转换成一个String对象,并两者串接.此时,任何类型都可以转换成String.[这里,我漏掉了"3"和"4"]
如果是基本数据类型,则如同首先转换成其包装类对象,如int x视为转换成Integer(x).
现在就全部统一到引用类型向String的转换了.关于+是串接还是加法,由操作数决定.1+2+str+3+4 就很容易知道是"3jf34".
按照上述说法,str = 1+2+str+3+4;语句似乎应该就应该生成5个String对象:
1+2 =3,then 3→Integer(3)→"3" in pool? [假设如此]
"3"+str(in heap) = "3jf" (in heap)
"3jf" +3 ,first 3→Integer(3)→"3" in pool? [则不创建] then "3jf3"
"3jf3"+4 create "4" in pool
then "3jf34"
这里我并不清楚3,4转换成字符串后是否在池中,所以上述结果仍然是猜测.
为了减少创建中间过渡性的字符串对象,提高反复进行串接运算时的性能,可以使用StringBuffer或者类似的技术.例如:对于 a + b,new StringBuffer().append(a).append(b).toString();
注意,对于基本类型和引用类型,在append(a)过程中仍然要先将参数转换,从这个观点看,str = 1+2+str+3+4;创建的字符串可能是"3","4"和"3jf34"[以及一个StringBuffer对象].
现在仍然不知道怎么回答str = 1+2+str+3+4;创建了多少String的对象,.或许,这个问题不需要过于研究.
3,这又不同:str = "3"+"jf"+"3"+"4";
如果是一个完全由字符串文字组成的表达式,则在编译时,已经被优化而不会在运行时创建中间字符串.测试代码如下:
String str1 ="3jf34";
String str2 ="3"+"jf"+"3"+"4";
if(str1 == str2) { System.out.println("str1 == str2"); }
else { System.out.println("think again"); }
if(str2.equals(str1)) System.out.println("yet str2.equals(str1)");
可见,str1与str2指向同一个对象。
对于String str2 ="3"+"jf"+"3"+"4";我们说仅仅创建一个对象.注意,"创建多少对象"的讨论是说运行时创建多少对象.
BTW:编译时优化
String x = "aaa " + "bbb ";
if (false) { x = x + "ccc "; }
x += "ddd ";
等价于: String x = "aaa bbb "; x = x + "ddd ";
//这个地方我自己进行了编译,不过和他的结论不一样,好像当用x+="ddd"的时候和直接的x="aaa"+"bbb"+"ddd" 不同,但是具体为什么我也不清楚,正在研究中...
4,不变类
String对象是不可改变的(immutable).不变类的关键是,对于对象的所有操作都不可能改变原来的对象。
1,类Sring、StringBuilder、StringBuffer的区别
2,switch语句能否作用在byte上,能否作用在long上,能否作用在String上?
3,String是最基本的数据类型吗
4,String s = "Hello";s = s + " world!";这两行代码执行后,原始的String对象中的内容到底变了没有?
5,是否可以继承String类?
6,String s = new String("xyz");创建了几个String Object? 二者之间有什么区别?
7,如何把一段逗号分割的字符串转换成一个数组?
8,数组有没有length()这个方法? String有没有length()这个方法?
9,下面这条语句一共创建了多少个对象:String s="a"+"b"+"c"+"d";
10,上机题
java语言中有四种不同的限定词,提供了四种不同的访问权限。
1) private
类中限定为private的成员,只能被这个类本身访问。如果一个类的构造方法声明为private,则其它类不能生成该类的一个实例。
2) default
类中不加任何访问权限限定的成员属于缺省的(default)访问状态,可以被这个类本身和同一个包中的类所访问。
3) protected
类中限定为protected的成员,可以被这个类本身、它的子类(包括同一个包中以 及不同包中的子类)和同一个包中的所有其他的类访问。
4) public
类中限定为public的成员,可以被所有的类访问。
限定词的范围表:
限定词 |
同一个类 |
同一个包的类 |
不同包的子类 |
不同包非子类 |
private |
yes |
|
|
|
default |
yes |
yes |
|
|
protected |
yes |
yes |
yes |
|
public |
yes |
yes |
yes |
yes |
volatile关键字
volatile是java提供的一种同步手段,只不过它是轻量级的同步, volatile只能保证多线程的内存可见性,不能保证多线程的执行有序性。而最彻底的同步要保证有序性和可见性,例如synchronized。
任何被volatile修饰的变量,都不拷贝副本到工作内存,任何修改都及时写在主存。因此对于Valatile修饰的变量的修改,所有线程马上就能看到,但是volatile不能保证对变量的修改是有序的。
当一个VolatileTest对象被多个线程共享,a的值不一定是正确的,因为a=a+count包含了好几步操作,而此时多个线程的执行是无序的,因为没有任何机制来保证多个线程的执行有序性和原子性。
volatile存在的意义是,任何线程对a的修改,都会马上被其他线程读取到,因为直接操作主存,没有线程对工作内存和主存的同步。所以,volatile的使用场景是有限的,在有限的一些情形下可以使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
1)对变量的写操作不依赖于当前值。
2)该变量没有包含在具有其他变量的不变式中
总之:
1、volatile适合直接赋值的场景,但是顺序可能会被打乱
2、volatile适合修饰的变量存在一定的计算当中,比如a=a+1,a++,包括变量为对象的多步骤操作。
3、volatile是java提供的一种同步手段,只不过它是轻量级的同步,为什么这么说,因为volatile只能保证多线程的内存可见性,不能保证多线程的执行有序性。而最彻底的同步要保证有序性和可见性,例如:synchronized。
1,作用域public,private,protected以及不写时的区别?
一、this调用本类中的属性,也就是类中的成员变量。
二、this调用本类中的其他方法;
三、this调用本类中的其他构造方法,调用时要放在构造方法的首行,否则会报错。
四、this作为返回值或者参数传递时,表示返回或传递当前类的引用。
五、注意匿名类和内部类中的中的this。这个this则指的是匿名类或非静态内部类本身。如果要使用外部类的方法和变量的话,则应该加上外部类的类名(例如:Strings.this.a1).
调用父类中的行为或属性。
1,调用父类的构造方法时,只能在子类的构造方法中调用,并且放在第一行;同时,如果this调用该类其他构造方法时,也必须放在构造方法第一行,此时,不能同super一起使用。
2,super可以显示调用父类中可见的行为和属性。
表示整体特征而不是个体特征时的修饰符。
一,静态与非静态的差别
1,空间分配时机:静态变量是在类加载的时候分配空间,非静态对象是在生成对象的时候分配空间。
2,空间分配方法:不管多少对象,静态变量只有一份(所有对象共享),非静态变量有多少对象就分配多少空间。
3,访问方式:
静态变量:类名.属性 比如Animal.COUNT
非静态变量:对象名.属性 比如a.name (通常用getXX()方法获得)。
二,静态方法和非静态方法的区别。
1,静态方法是通过类名来表用,非静态方法是通过对象来调用。
2,静态方法中不能访问本类的非静态成员( 属性和方法 ),但非静态方法可以访问静态成员。
3,静态方法不存在多态特性,也就是静态方法无法被子类覆盖,父类对象调用此方法还是父类的(但最好用类名调用)。
三,静态代码块
1,静态代码块在类被加载时被系统自动执行。
2,一般可以在静态代码中给属性赋值。
小结:
只有非静态方法有多态,而静态方法、静态属性、非静态属性都没有多态。
父类:Main.java, public String a = "main";
子类:Sub.java, public String a = "sub";
main(): Main main = new Sub(); Sub sub = new Sub(); System.out.println(main.a); // main
System.outprintln(sub.a); // sub
1,修饰属性:属性不可变,并且属性在声明的时候必须被初始化。
与static连用:要么直接赋值,要么在静态代码块中赋值。
不与static连用:要么直接赋值,只能在所有的构造方法中赋值。
2,修饰方法:方法不能被覆盖。
3,修饰类:类不能被继承。
4,修饰局部变量:局部变量不可变(常量)。
1,修饰类:表示该类为抽象类,即使该类没有抽象方法,抽象类也不能被实例化。
2,修饰方法:表示该方法是抽象方法,无方法体;若一个类有一个抽象方法,该类必须为抽象类,抽象方法由子类实现。
注:final,abstract 不能共同修饰一个类或方法。
1,是一种抽象的数据类型,特殊的抽象类( 所有方法都为抽象方法)
2,接口中所有属性都是public static final (静态常量)。
3,一个类不能继承一个父类,但可以实现多个接口(接口之间用“,”隔开)。
4,接口之间可以多继承,比如
Interface F1{ } interface F2{ }
Interface F3 extends F1, F2{ } // 同时继承了F1和F2接口
封装、继承、多态
1,隐藏类的内部实现,只提供给外部一个接口方法该类。
2,目的是避免外部直接方法修改类的变量。
3,维护性,同时也是为了当业务改变时,只需要修改内部实现,对外部无影响。
1,被继承是父类,继承的父类的类是子类。每个类只能直接继承一个类。
2,在构造子类时,必须先构造一个父类对象(在子类的构造方法中调用父类的构造方法,并且super要放在第一行,不能与this一起用,为了在构造子类时给父类中定义的变量赋值)。
3,子类的特点:
A, 任何子类的构造方法都会调用父类的构造方法。
B, 任何子类的构造方法的第一行必须是this(..,..)或super(..,..)的调用。若不写,则系统会隐含的调用super().
4,构造一个子类对象其它也只是创建了一个对象,只不过父对象是子对象的一个部分。
{
注: 为什么子类的构造方法一定要调用父类的构造方法呢?
答案:从反方向来讲,JVM会先创建一个所有类的父类对象出来,然后再对这个 对象扩展,最后生成子类对象,也就是说“没有父哪来的子呢”这个意思。
}。
5,继承的目的是未来实现代码复用,子类可以访问父类所有可见的成员。
1,简单的说就是同一继承树上不同对象针对同一行为的不同表现。
2,多态基本分为两种;对类来说,是方法重载;对继承来说,是方法覆盖。
3,表现对象多态的一种形式,把子类对象当做父类对象的一种形式;父类名 对象= new 子类名(); 但这样的话,此对象不能调用父类中没有的方法。
4,多态定理
A, 如果我们把子类对象当作父类对象来看,并且子类没有覆盖父类的任何方法。那么就只能访问父类中已有定义的属性和方法(不能访问子类扩展的属性和方法)。
B, 如果子类覆盖了父类的方法,再把子类对象当作父类对象去调用该方法时,调用的是子类覆盖后的方法。
{
注:编译时类型:在写代码编译过程中,编译器把这个对象当作父类对象运行时类型:在代码运行过程中,JVM把这个对象当作子类对象。
}
构成覆盖条件:
1,方法名、参数表(含顺序):相同。
2,访问限制符:相同或更宽。
3,返回值类型:相同或者子类返回的类型是父类返回类型的子类。
4,子类抛出的异常应该是父类抛出异常或其子类。
1,方法名:相同
2,方法参数:参数的个数或类型不同,或不同类型参数之间的顺序不同。
{
注:只是返回值类型不同,不能构成重载。
}
1, 多态的表现
2, 重载与重写(覆盖)的区别
3, 实现代码重用的两种机制
介绍了三种修改现有代码提高其可重用性的方法,它们分别是:改写类的实例方法,把参数类型改成接口,选择最简单的参数接口类型。
措施一:改写类的实例方法
通过类继承实现代码重用不是精确的代码重用技术,因此它并不是最理想的代码重用机制。换句话说,如果不继承整个类的所有方法和数据成员,我们无法重用该类里面的单个方法。继承总是带来一些多余的方法和数据成员,它们总是使得重用类里面某个方法的代码复杂化。另外,派生类对父类的依赖关系也使得代码进一步复杂化:对父类的改动可能影响子类;修改父类或者子类中的任意一个类时,我们很难记得哪一个方法被子类覆盖、哪一个方法没有被子类覆盖;最后,子类中的覆盖方法是否要调用父类中的对应方法有时并不显而易见。
任何方法,只要它执行的是某个单一概念的任务,就其本身而言,它就应该是首选的可重用代码。为了重用这种代码,我们必须回归到面向过程的编程模式,把类的实例方法移出成为全局性的过程。为了提高这种过程的可重用性,过程代码应该象静态工具方法一样编写:它只能使用自己的输入参数,只能调用其他全局性的过程,不能使用任何非局部的变量。这种对外部依赖关系的限制简化了过程的应用,使得过程能够方便地用于任何地方。当然,由于这种组织方式总是使得代码具有更清晰的结构,即使是不考虑重用性的代码也同样能够从中获益。
在Java中,方法不能脱离类而单独存在。为此,我们可以把相关的过程组织成为独立的类,并把这些过程定义为公用静态方法。
A. new 一个对象的时候-------加载
B. 访问类中静态成员(方法和属性),此时没有创建对象-------加载
C. 声明一个类的引用-------不载入
D. 创建子类,先载入父类,再载入子类
E. 父类中的公开静态方法,子类继承(子类中没有该静态方法),使用子类的类名调用此方法,只加载父类。 例如,父类:class Super{ public static m(){} } 子类:class Sub extends Super{};
主函数中运行代码: Sub.m(); //加载了父类之后,虚拟机已经加载了该方法,就不会再加载子类
1. 类加载,执行静态语句块和静态的属性赋值(先父类后子类)
2. 预开空间,所有属性空间设零值
3. 实例化对象:(先父类后子类): a,初始化所有的属性和非静态语句块(自上而下执行) b,构造函数
具体顺序是:先加载父类的static代码块,再加载子类的static代码块;
再加载父类的代码块,再调用父类的构造方法;
在加载子类的代码块,再调用子类的构造方法。(验证过)
1. 加载静态成员/代码块:
先递归地加载父类的静态成员/代码块(Object 的最先);再依次加载到本类的静态成员。
同一个类里的静态成员/代码块,按写代码的顺序加载。
如果其间调用静态方法,则调用时会先运行静态方法,再继续加载。
对象调用静态成员,以声明对象的类型为准;如果使用类名调用,就是调用该类的静态成员。
2. 加载非静态成员/代码块:
先递归地加载父类的非静态成员/代码块(Object 的最先);再依次加载到本类的非静态成员。
同一个类里的非静态成员/代码块,按写代码的顺序加载。
3. 调用构造方法:
先递归调用父类构造方法(Object 最先);默认调用父类空参的,也可在第一行写明调用父类某个带参的。
再依次到本类的构造方法; 构造方法内, 也可在第一行写明调用某个本类其它的构造方法。\
1, 其调用按多态用法:只有非静态方法有多态;而静态方法、静态属性、非静态属性都没有多态。
2, 由于构造子类时会先构造父类;而构造父类时,其所用的静态成员和非静态属性是父类的,但非静态方法却是子类的;
3, 由于构造父类时,子类并未加载;如果此时所调用的非静态方法里有成员,则这个成员是子类的,且非静态属性是默认初始值的。
4, 成员,包括变量和方法; 成员变量,包括实例变量和静态变量
标签:
原文地址:http://www.cnblogs.com/horsemen/p/5734807.html