Java中的一些小问题

只是记录几个在学习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改变类变量,其他对象会得到改变之后的数据
	}
}


2.为什么“类方法中不能访问非静态变量”?

本来自己准备写写理解,加上代码来做解释。但是看到别的大神对此解释的非常清楚,所以准备搬过来。
为什么不能从静态的方法里面调用非静态方法,或变量?   (没有找到原作者,对作者抱歉)

程序都将在内存中执行,变量只有在内存中占有一席之地时才能被访问。
类的静态成员(类变量、类方法)属于类本身,在类加载时就会被分配内存,可以通过类名直接访问;非静态成员(成员变量,成员方法)属于类实例化的对象,只有在类产生对象时(类进行实例化时)时才会产生,然后通过类的对象去访问。
在一个类的静态成员中去访问非静态成员会出错的原因是:静态成员在类加载时就已经创建了,而非静态成员要等到类进行实例化、创建对象的时候才会产生。简单的说,非静态成员不存在的时候静态成员就已经存在了。访问一个不存在的东西当然会出错。

而类是在什么时候加载的呢?

引导类加载器负责加载的核心类比如 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()方法执行完,整个程序退出。

再加一句:super关键字有两种意义:–调用父类的方法–调用父类的构造器。但是super并不表示一个指向对象的引用,它只是一个特殊的关键字,用来告诉编译器,现在要调用的是父类的方法。

3.如何准确记忆Java中各个访问修饰符的访问范围?

虽然学习了修饰符的访问范围,但是总是记忆不清楚。所以想小小总结一下,加深一下印象。

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("我是小狗,汪汪!");
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章