只是记录几个在学习Java的过程中思考的一些问题,以及自己的理解。
1.Java 局部变量、实例变量、类变量(静态变量)区别?
2.为什么“类方法中不能访问非静态变量”?
3.如何准确记忆Java中各个访问修饰符的访问范围?
4.如何理解“重载”与“覆盖”?
1.Java 局部变量、成员变量、类变量(静态变量)区别?
局部变量:在Java方法中的变量。其作用域只在本方法内。
成员变量:是独立于方法之外的,不会有static修饰,也称作“实例变量”,它就是对象的私有变量。
类变量:类变量独立于方法之外,也称作“静态变量”。用static修饰。static 表示“全局的”“静态的”,用来修饰成员变量,成员方法,或者静态代码块。
成员变量和类变量的区别?
其根本区别在于,类变量是类所实例化的所有对象的公有变量,任何一个对象对该变量进行修改以后,其他对象得到的都是被修改之后的数据;成员变量是对象私有的变量,某一对象对成员变量进行修改,只影响该对象成员变量的数据,不影响其他对象。
Code 说明:
class Student{
int age; //成员变量,“实例变量”
static int totalAge; //类变量,“静态变量”
public void getTime()
{
float time=2016; //局部变量,作用域在本方法以内
System.out.println("time="+time);
}
}
public class Test6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student s1=new Student();
Student s2=new Student();
s1.age=1;
s1.totalAge=1;
System.out.println("s2.age="+s2.age); //结果是 0
//成员变量s1.age改变,只会影响其s1.age,对象s2的成员变量s2.age不会有任何改变
System.out.println("s2.total="+s2.totalAge); //结果是1
//s1改变类变量,其他对象会得到改变之后的数据
}
}
由引导类加载器负责加载的核心类比如 String 类在 JVM 启动时(main 方法开始执行前)就会被加载,其它类在使用前(new 它对象或调用其静态方法访问静态域等等前)会被动态加载,要注意的是子类被加载前它的所有父类要根据由父到子的顺序被逐一加载。
class A1
{
public static int a=5;
}
class B1 extends A1
{
public static int a=8;
void print(){
System.out.println(super.a);
System.out.println(a);
}
}
public class TestStatic
{
public static void main(String args[])
{
System.out.println("b.a="+B1.a);
System.out.println("b.a="+A1.a);
new B1().print();
}
}
说明如下:
在doc环境下,
Java TestStatic时,
虚拟机会先加载TestStatic类,此时虚拟机会先看看TestStatic类有没有静态的字段,
没有。JVM直接执行main 方法,
main方法中第一句代码是打印B1.a,
虚拟机便会去找类B1,找到类B1时,虚拟机发现B1的父亲是A1,
于是父亲优先,先加载A1,
同样,在加载A1时,会看看A1中有什么静态的东西,有,
static int a = 5;
a是静态的,先加载,当把静态的字段加载完后,一个类就算加载完了,
所以A1已经加载完毕,以后不用在加载了。
父亲加载完了,轮到B1了,同样先看看里面有什么静态的字段,有,
static int a = 8;
此时B1也加载完毕了。
第一条打印语句到此时也执行完毕了,
轮到第二条打印语句了。
当执行new B1().print();这句时,
会发生动态绑定,
此时会有一个代表B1对象的this对象传递给print()方法,
所以print()方法中的
System.out.println(a);
其实是,
System.out.println(this.a);
会打印出一个8出来。
至于super.a就简单了,
打印父类中的a,
结果是5.
到此,main()方法执行完,整个程序退出。
虽然学习了修饰符的访问范围,但是总是记忆不清楚。所以想小小总结一下,加深一下印象。
Java 里的控制访问范围的修饰符总共有四个,从控制范围从小到大依次是private,默认,protected,public。但是比如protected 其访问范围到底是多大,同类?同包?不同包?还是记忆不清楚。
总结了一个表,如下:
做个说明:
其实对于private,default,protected,public控制范围由小到大早已烂熟于心,但对于同类,同包,子类,不同包还没有达到那个地步。
将“同类,同包,子类,不同包”形象比作四种关系:自己和“自己,夫妻,子女,自己的朋友”,其亲密程度是由近到远,但是范围在扩大。
1.private 私有的,就自己能访问,别人谁都不行。访问范围最小,只能是同类之间访问。
2.default 默认的,就像亲密付,只有跟自己非常亲密的人才行,比如妻子。访问范围比private稍扩大,在同类同包都可以访问。
3.protected 受到保护的,就像自己家的东西只有家人(自己老婆还有孩子)才可以分享。访问范围比default 更大,在同类同包子类可访问。
4.public 公有的,除了自己和家人以外,认识自己的朋友都可以看。访问范围比default再大一点,在同类,同包,子类,不同包可以访问。
4.如何理解“重载”与“覆盖”?
重载(Overloading )
简单来讲,就是类的同一种功能的多种实现形式,具体采用哪一种,取决于调用者传递的参数。
再具体一点:
百度百科给出的定义:方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。调用重载方法时,Java编译器能通过检查调用的方法的参数类型和个数选择一个恰当的方法。
归纳几个要点:
1.重载要求,在同一个类中,定义多个同名方法。
2.同名方法具有不同的参数类型/个数。
3.返回类型,可以相同也可以不同。不能以返回类型来区分重载函数。
public class Test8 {
public static void main(String[] args) {
// TODO Auto-generated method stub
A a = new A();
System.out.println("得到较大的数字:"+a.getMax(11, 12.5f));;
}
}
class A{
//返回较大的整数
int getMax(int a,int b){
if(a>b){
return a;
}else{
return b;
}
}
//返回较大的小数
float getMax(float a,float b){
if(a>b){
return a;
}else{
return b;
}
}
}
覆盖(Overriding)
简单的讲,就是如果子类中的某个方法和父类中的名称、返回类型、参数都一样。那么我们就说子类的这个方法覆盖了父类的那个方法。
PS:覆盖是为了解决,子类在继承父类以后,虽然有了父类的所有方法,但是希望对该方法做一定的修改而产生的。覆盖也称作“重写”。
要点总结如下:
1.子类中的方法和父类的某一个方法名称、返回类型、参数都一样,则新方法会覆盖父类中的方法。
2.如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
3.子类中方法的修饰符访问范围>=父类中该方法的访问范围。
public class Test9 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Cat c=new Cat();
c.speak();
}
}
class Animal{
protected void speak(){
System.out.println("作为动物,我不知道怎么叫!");
}
}
class Cat extends Animal{
public void speak(){ //注意:public>protected 子类方法可以扩大,但不能缩小访问范围
System.out.println("我是小猫,喵喵!");
}
}
class Dog extends Animal{
protected void speak(){
System.out.println("我是小狗,汪汪!");
}
}