为什么类成员方法只能访问类成员变量,而不能访问实例成员变量?

guolicheng123456 2009-03-28 10:49:17
为什么类成员方法只能访问类成员变量,而不能访问实例成员变量?
类成员变量和实例成员变量在内存分配上的区别我知道;但是类成员方和和实力成员方法的访问变量的机制不明白。
请大家指点~
...全文
1453 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
康派尔 2011-06-16
  • 打赏
  • 举报
回复
类成员变量和类方法一般指的是类中的静态方法或静态变量,或者是静态内部类。静态成员是在java虚拟机加载类时,初始化的。可以全局通过类名访问,试想一下当你掉用了一个类的静态方法时,而这个方法用到了类的实例成员,而这个类的实例你还没有new出来,岂不是不安全了,所以编译器在编译的时候会检查你是否在静态成员里用到了实例成员,如果有责编译通不过的。
guolicheng123456 2009-04-09
  • 打赏
  • 举报
回复
谢谢babybabyface,我就是想知道他们在内存中的关系。

也谢谢楼上的其他朋友
guolicheng123456 2009-03-28
  • 打赏
  • 举报
回复
还是不明白~
lliiqiang 2009-03-28
  • 打赏
  • 举报
回复 1
实例变量只有在创建实例的时候才会被创建,而静态成员是加载类的时候被创建。所以有了静态成员未必据有实例变量,即使有了实例变量,那么多实例,它哪知道访问哪个实例变量
lic_go 2009-03-28
  • 打赏
  • 举报
回复
public class Hello{
public static void main(String[] args){ //(1)
System.out.println("Hello,world!"); //(2)
}
}

看过这段程序,对于大多数学过Java 的从来说,都不陌生。即使没有学过Java,而学过其它的高级语言,例如C,那你也应该能看懂这段代码的意思。它只是简单的输出“Hello,world”,一点别的用处都没有,然而,它却展示了static关键字的主要用法。

在1处,我们定义了一个静态的方法名为main,这就意味着告诉Java编译器,我这个方法不需要创建一个此类的对象即可使用。你还得你是怎么运行这个程序吗?一般,我们都是在命令行下,打入如下的命令(加下划线为手动输入):

javac Hello.java
java Hello
Hello,world!

这就是你运行的过程,第一行用来编译Hello.java这个文件,执行完后,如果你查看当前,会发现多了一个Hello.class文件,那就是第一行产生的Java二进制字节码。第二行就是执行一个Java程序的最普遍做法。执行结果如你所料。在2中,你可能会想,为什么要这样才能输出。好,我们来分解一下这条语句。(如果没有安装Java文档,请到Sun的官方网站浏览J2SE API)首先,System是位于java.lang包中的一个核心类,如果你查看它的定义,你会发现有这样一行:public static final PrintStream out;接着在进一步,点击PrintStream这个超链接,在METHOD页面,你会看到大量定义的方法,查找println,会有这样一行:

public void println(String x)。

好了,现在你应该明白为什么我们要那样调用了,out是System的一个静态变量,所以可以直接使用,而out所属的类有一个println方法。

静态方法

通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法。如下所示:

class Simple{
static void go(){
System.out.println("Go...");
}
}
public class Cal{
public static void main(String[] args){
Simple.go();
}
}

调用一个静态方法就是“类名.方法名”,静态方法的使用很简单如上所示。一般来说,静态方法常常为应用程序中的其它类提供一些实用工具所用,在Java的类库中大量的静态方法正是出于此目的而定义的。

静态变量

静态变量与静态方法类似。所有此类实例共享此静态变量,也就是说在类装载时,只分配一块存储空间,所有此类的对象都可以操控此块存储空间,当然对于final则另当别论了。看下面这段代码:

class Value{
static int c=0;
static void inc(){
c++;
}
}
class Count{
public static void prt(String s){
System.out.println(s);
}
public static void main(String[] args){
Value v1,v2;
v1=new Value();
v2=new Value();
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1.inc();
prt("v1.c="+v1.c+" v2.c="+v2.c);
}
}

结果如下:

v1.c=0 v2.c=0
v1.c=1 v2.c=1

由此可以证明它们共享一块存储区。static变量有点类似于C中的全局变量的概念。值得探讨的是静态变量的初始化问题。我们修改上面的程序:

class Value{
static int c=0;
Value(){
c=15;
}
Value(int i){
c=i;
}
static void inc(){
c++;
}
}
class Count{
public static void prt(String s){
System.out.println(s);
}
Value v=new Value(10);
static Value v1,v2;
static{
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1=new Value(27);
prt("v1.c="+v1.c+" v2.c="+v2.c);
v2=new Value(15);
prt("v1.c="+v1.c+" v2.c="+v2.c);
}

public static void main(String[] args){
Count ct=new Count();
prt("ct.c="+ct.v.c);
prt("v1.c="+v1.c+" v2.c="+v2.c);
v1.inc();
prt("v1.c="+v1.c+" v2.c="+v2.c);
prt("ct.c="+ct.v.c);
}
}

运行结果如下:

v1.c=0 v2.c=0
v1.c=27 v2.c=27
v1.c=15 v2.c=15
ct.c=10
v1.c=10 v2.c=10
v1.c=11 v2.c=11
ct.c=11

这个程序展示了静态初始化的各种特性。如果你初次接触Java,结果可能令你吃惊。可能会对static后加大括号感到困惑。首先要告诉你的是,static定义的变量会优先于任何其它非static变量,不论其出现的顺序如何。正如在程序中所表现的,虽然v出现在v1和v2的前面,但是结果却是v1和v2的初始化在v的前面。在static{后面跟着一段代码,这是用来进行显式的静态变量初始化,这段代码只会初始化一次,且在类被第一次装载时。如果你能读懂并理解这段代码,会帮助你对static关键字的认识。在涉及到继承的时候,会先初始化父类的static变量,然后是子类的,依次类推。

通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。如下代码所示:

public class StaticCls{
public static void main(String[] args){
OuterCls.InnerCls oi=new OuterCls.InnerCls();
}
}
class OuterCls{
public static class InnerCls{
InnerCls(){
System.out.println("InnerCls");
}
}
}

输出结果会如你所料:

InnerCls
lic_go 2009-03-28
  • 打赏
  • 举报
回复
内部类的存在是基于外部类的实例存在的,内部类就好像是跟这个外部类的成员变量或方法一样存在
他的存在是为了extends一些类或实现某些接口
试想一个成员方法怎么可以访问到人家的变量,
她能访问的就是类的成员和方法,如果真的要访问到就要通过间接访问(通过该局部变量的方法或其它来访问)

内部类在编译后都会产生一个新的Class文件的.

匿名类在概念上与命名内类一样,即完全在另一个类的界限内定义的类.只是在句法上与命名的内部类不同
moolf 2009-03-28
  • 打赏
  • 举报
回复
找本基础点的教程看看 你会明白很多
babybabyface 2009-03-28
  • 打赏
  • 举报
回复
要理解三个区域:方法区 栈 堆

类的方法信息和类的static变量放在 方法区
对象的实例变量以及对方法地址的引用放在 堆
方法执行时局部变量及对象的引用地址压入 栈

为什么类成员方法只能访问类成员变量,而不能访问实例成员变量? static方法的执行不依赖对象,因此跟堆区没有联系,自然不能调用位于堆区的实例变量。

如果想深入理解 建议读下 《深入JAVA虚拟机》中类与对象生命周期几章
孙卫琴的JAVA基础的书也参考这本书讲了点

lxm520910 2009-03-28
  • 打赏
  • 举报
回复
你能明白什么是类变量,什么是成员变量吗?

如果你能理解它们的区别,你就能搞懂你那问题了。

之所以称类变量和方法,因为他们属于类,他们可以不实例化,直接调用;

称成员变量和方法,那是因为他们属于成员,也就是要实例化。

你没实例化就调用成员变量和方法,就会出问题的。你调用类方法的时候,类方法间调用了成员变量(没实例化吧),那该报错吧?
starscc 2009-03-28
  • 打赏
  • 举报
回复
在static里(不管是域还是方法)都只能访问static成员,可以看一下类加载过程
lxm520910 2009-03-28
  • 打赏
  • 举报
回复
你能明白什么是类变量,什么是成员变量吗?
本课程采用了漫画+动手实操+练习讲授Python编程技能。课程简介:第6章 容器型数据6.1 序列6.1.1 序列的索引操作6.1.2 加与乘操作6.1.3 切片操作6.1.4 成员测试6.2 列表6.2.1 创建列表6.2.2 追加元素6.2.3 插入元素6.2.4 替换元素6.2.5 删除元素6.3 元组6.3.1 创建元组6.3.2 元组拆包6.4 集合6.4.1 创建集合6.4.2 修改集合6.5 字典6.5.1 创建字典6.5.2 修改字典6.5.3 访问字典视图6.6 动动手 —— 遍历字典6.7 练一练第7章 字符串7.1 字符串的表示方式7.1.1 普通字符串7.1.2 原始字符串7.1.3 长字符串7.2 字符串与数字的相互转换7.2.1 将字符串转换为数字7.2.2 将数字转换为字符串7.3 格式化字符串7.3.1 使用占位符7.3.2 格式化控制符7.4 操作字符串7.4.1 字符串查找7.4.2 字符串替换7.4.3 字符串分割7.5 动动手 —— 统计英文文章中单词出现的频率7.6 练一练第8章 函数8.1 定义函数8.2 调用函数8.2.1 使用位置参数调用函数8.2.2 使用关键字参数调用函数8.3 参数的默认值8.4 可变参数8.4.1 基于元组的可变参数( *可变参数)8.4.2 基于字典的可变参数( **可变参数)8.5 函数中变量的作用域8.6 函数型8.6.1 理解函数型8.6.2 过滤函数filter()8.6.3 映射函数map()8.7 lambda()函数8.8 动动手 —— 使用更多的lambda()函数8.9 练一练第9章 与对象9.1 面向对象9.2 定义9.3 创建对象9.4 的成员9.4.1 实例变量9.4.2 构造方法9.4.3 实例方法9.4.4 变量19.5 封装9.5.1 私有变量9.5.2 私有方法9.5.3 使用属性9.6 继承性9.6.1 Python中的继承9.6.2 多继承9.6.3 重写方法9.7 多态性9.7.1 继承与多态9.7.2 鸭子型测试与多态9.8 练一练第10章 异常处理9.8 练一练10.1 第一个异常 —— 除零异常10.2 捕获异常110.2.1 try-except语句10.2.2 多个except代码块10.2.3 多重异常捕获10.2.4 try-except语句嵌套10.3 使用finally代码块释放资源10.4 自定义异常10.5 动动手 —— 手动引发异常10.6 练一练

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧