回过头来再看的时候真的已经不知道它们分别是什么东西了,JLS上也就只是说它们是关键字。但是它们真正到底是什么呢?
对于super,《The Java Programming Language》上这样说:In field access and method invocation, super acts as a reference to the current object as an instance of its superclass.可以理解为在需要访问the hidden field和进行父类方法调用的时候,super表现为指向作为父类的一个实例的当前对象的一个引用。所以super只是act as a reference,但不是reference,对吗?我们也不可以将super赋给一个父类变量,比如在子类中:Super s = super;(报错)。当我们在构造方法中使用super()或其他形式的时候super又是什么呢?
对于this,JLS上这样表述:When used as a primary expression, the keyword this denotes a value that is a reference to the object for which the instance method was invoked (§15.12), or to the object being constructed.这里:this也只是代表一个引用的值,还是没说this除了是keyword外还是什么,但是又说的this的类型。反正搞得一团乱,下面的代码输出的结果我也不理解:class Super {
}class SubClass extends Super{
public void foo() {
System.out.println(this.getClass());
System.out.println(super.getClass());
}
}希望大家帮忙解惑,说说它们是什么。怎么使用它们就不用说了,所有的书上都差不多教我们怎么用了。谢谢~
对于super,《The Java Programming Language》上这样说:In field access and method invocation, super acts as a reference to the current object as an instance of its superclass.可以理解为在需要访问the hidden field和进行父类方法调用的时候,super表现为指向作为父类的一个实例的当前对象的一个引用。所以super只是act as a reference,但不是reference,对吗?我们也不可以将super赋给一个父类变量,比如在子类中:Super s = super;(报错)。当我们在构造方法中使用super()或其他形式的时候super又是什么呢?
对于this,JLS上这样表述:When used as a primary expression, the keyword this denotes a value that is a reference to the object for which the instance method was invoked (§15.12), or to the object being constructed.这里:this也只是代表一个引用的值,还是没说this除了是keyword外还是什么,但是又说的this的类型。反正搞得一团乱,下面的代码输出的结果我也不理解:class Super {
}class SubClass extends Super{
public void foo() {
System.out.println(this.getClass());
System.out.println(super.getClass());
}
}希望大家帮忙解惑,说说它们是什么。怎么使用它们就不用说了,所有的书上都差不多教我们怎么用了。谢谢~
“我们也不可以将super赋给一个父类变量,比如在子类中:Super s = super;(报错)。当我们在构造方法中使用super()或其他形式的时候super又是什么呢?”我来回答:首先:this和super是一个特殊的变量,它存储的是引用,这个变量的产生又依赖对象实例的产生(说它们特殊是因为这两个变量是jvm帮我们完成的,我们根本不需要自己去定义也无法去定义。)你这里“Super s = super” 首先 “Super s”java编译器会把它理解为声明一个叫s 的Super类的引用
显然你没定义自然找不到,加入你定义了一个Super的类,那好!我们看 “= super”,这里面的super java编辑器一定会把它当成是 关键字super,关键字super能这样用吗?你可能会说他存储的是引用啊,那我把一个引用赋给一个变量可以吧!问题是:首先:你定义的类Super的引用应该是new Super()来产生的,跟这个关键字super里的引用是八辈子打不到一块去的。
第二,你这super我们已经说过了他存在的意义2楼,而且它依赖于先产生对象实例,这也非常吻合它存在的意义。所以你这句 "Super s = super"可以说是 “不知道在说什么”。
一个class,如果继承于其他类,那么前面的内存部分是父类的东西,后面部分才是自己的,当你访问父类,只要能把this转成父类引用,编译器根本不会意识到目前在操作的是子类,super = (father)this。 upcast,
为了RTTI,需要downcast,编译器会对这两个类作内部作一些处理,使他们能表现正确的行为,比如多重继承,虚拟继承等,先忽略这些,父类和子类就是一个简单的内存空间堆叠关系,并没有真正“产生”一个父类。
}class SubClass extends Super{
public void foo() {
System.out.println(this.getClass());
System.out.println(super.getClass());
}
}
在你这段代码里,
this就是class SubClass这个类(的对象的引用)
super就是class Super这个类(的对象的引用)而
System.out.println(this.getClass());
System.out.println(super.getClass());
的执行结果完全看你的用哪个对象在调用getClass()这个方法比如你实例化了一个SubClass的对象sub
你sub.foo();
那this.getClass()的结果我相信你完全能理解
应该是sub这个对象对应的类——SubClass那super.getClass()的结果呢?
楼主的想法可能是这样——Super
但是这是不对的,
因为这里仅仅是在sub这个对象里调用了父类中的getClass()这个方法
而这个方法的意义是返回你当前对象对应的类
所以super.getClass()的结果
应该是sub这个对象(当前对象)对应的类——SubClass至于super()这是构造函数中的特定用法
表示调用父类的构造函数,
必须出现(如果出现的话)子类构造函数的第一行
2、两者依赖于对象实例的产生,由jvm完成这套机制。
getclass返回的是运行时的对象的类,而上述程序运行时的对象是sub,所以都返回sub
System.out.println(this.getClass());
System.out.println(super.getClass());
}}class SubClass extends Super { public static void main(String[] args) {
new SubClass().foo();
}}这个结果还是一样的。说以导致getClass输出结果一致本质原因是 方法的覆盖
super调用老子的东东。。
this就儿子自己玩自己的
super就是class Super这个类(的对象的引用)而
System.out.println(this.getClass());
System.out.println(super.getClass());
的执行结果完全看你的用哪个对象在调用getClass()这个方法比如你实例化了一个SubClass的对象sub
你sub.foo();
那this.getClass()的结果我相信你完全能理解
应该是sub这个对象对应的类——SubClass那super.getClass()的结果呢?
楼主的想法可能是这样——Super
但是这是不对的,
因为这里仅仅是在sub这个对象里调用了父类中的getClass()这个方法
而这个方法的意义是返回你当前对象对应的类
所以super.getClass()的结果
应该是sub这个对象(当前对象)对应的类——SubClass至于super()这是构造函数中的特定用法
表示调用父类的构造函数,
必须出现(如果出现的话)子类构造函数的第一行
this是当前类的
(1)this调用本类中的属性,也就是类中的成员变量。——this.成员变量名(2)this调用本类中的其他方法——this.成员方法名(参数) (3)this调用本类中的其他构造方法——this(参数表) (4)返回对象的值——return thissuper表示父类对象(1)引用父类的成员变量——super.成员变量(2)调用父类的成员方法——super.成员方法名(参数表)(3)调用父类的构造方法——super(参数表)注意!!子类构造方法中的this()和super()调用只能有一个,不能同时使用
super父类对象的引用
private int i=2;
public Sup(){
this.foo();
}
public void foo(){
System.out.println(i);
}
}
public class test1 extends Sup{
private int i=22;
public test1(){
//System.out.println("hello");
i=222;
}
public void foo(){
System.out.println(i);
}
public static void main(String args[]){
new test1();
//
}
}大家把这个例子跑一遍 希望对你们有所帮助
而是说this表示正在编译的类
上面那个文件输出之后会得到0
[code=Java0]
class Sup{
private int i=2;
public Sup(){
this.foo();
}
public void foo(){
System.out.println(this.i);
}
[/code]
super指向父类(基类)的对象
return this;可以
但return super;就不行 是这个原因吗?
同意,我原来也是一直以为super是父类的引用,学习了!!!
一、this
Java关键字this只能用于方法方法体内。当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配一个引用自身的指针,这个指针的名字就是this。因此,this只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现this,这在“Java关键字static、final使用总结”一文中给出了明确解释。并且this只和特定的对象关联,而不和类关联,同一个类的不同对象有不同的this。下面给出一个使用this的综合实例,以便说明问题:
package org.leizhimin;
public class Test6 {
private int number;
private String username;
private String password;
private int x = 100;
public Test6(int n) {
number = n; // 这个还可以写为: this.number=n;
}
public Test6(int i, String username, String password) {
// 成员变量和参数同名,成员变量被屏蔽,用"this.成员变量"的方式访问成员变量.
this.username = username;
this.password = password;
}
// 默认不带参数的构造方法
public Test6() {
this(0, "未知", "空"); // 通过this调用另一个构造方法
}
public Test6(String name) {
this(1, name, "空"); // 通过this调用另一个构造方法
}
public static void main(String args[]) {
Test6 t1 = new Test6();
Test6 t2 = new Test6("游客");
t1.outinfo(t1);
t2.outinfo(t2);
}
private void outinfo(Test6 t) {
System.out.println("-----------");
System.out.println(t.number);
System.out.println(t.username);
System.out.println(t.password);
f(); // 这个可以写为: this.f();
}
private void f() {
// 局部变量与成员变量同名,成员变量被屏蔽,用"this.成员变量"的方式访问成员变量.
int x;
x = this.x++;
System.out.println(x);
System.out.println(this.x);
}
//返回当前实例的引用
private Test6 getSelf() {
return this;
}
}
运行结果如下:-----------
0
未知
空
100
101
-----------
0
游客
空
100
101
看着上面的例子,说明在什么情况下需要用到this:
第一、通过this调用另一个构造方法,用发是this(参数列表),这个仅仅在类的构造方法中,别的地方不能这么用。
第二、函数参数或者函数中的局部变量和成员变量同名的情况下,成员变量被屏蔽,此时要访问成员变量则需要用“this.成员变量名”的方式来引用成员变量。当然,在没有同名的情况下,可以直接用成员变量的名字,而不用this,用了也不为错,呵呵。
第三、在函数中,需要引用该函所属类的当前对象时候,直接用this。
其实这些用法总结都是从对“this是指向对象本身的一个指针”这句话的更深入的理解而来的,死记不然容易忘记而且容易搞错,要理解!
二、super
super关键和this作用类似,是被屏蔽的成员变量或者成员方法或变为可见,或者说用来引用被屏蔽的成员变量和成员成员方法。
不过super是用在子类中,目的是访问直接父类中被屏蔽的成员,注意是直接父类(就是类之上最近的超类)。下面是一个综合运用super的例子,有两个类:一个Father类,一个Father类的子类Son,通过这两个类完全演示了super的用法,一下是代码:
package org.leizhimin;
public class Father {
public String v="Father";
public String x="输出了Father类的public成员变量x!!!";
public Father() {
System.out.println("Father构造方法被调用!");
}
public Father(String v){
this.v="Father类的带参数构造方法!运行了.";
}
public void outinfo(){
System.out.println("Father的outinfo方法被调用");
}
public static void main(String[] args) {
// TODO 自动生成方法存根
}
}
package org.leizhimin;
public class Son extends Father{
public String v="Son";
public Son() {
super(); //调用超类的构造方法,只能放到第一行.
System.out.println("Son无参数构造方法被调用!");
//super(); //错误的,必须放到构造方法体的最前面.
}
public Son(String str){
super(str);
System.out.println("Son带参数构造方法被调用!");
}
//覆盖了超类成员方法outinfo()
public void outinfo(){
System.out.println("Son的outinfo()方法被调用");
}
public void test(){
String v="哈哈哈哈!"; //局部变量v覆盖了成员变量v和超类变量v
System.out.println("------1-----");
System.out.println(v); //输出局部变量v
System.out.println(this.v); //输出(子类)成员变量v
System.out.println(super.v); //输出超类成员变量v
System.out.println("------2-----");
System.out.println(x); //输出超类成员变量v,子类继承而来
System.out.println(super.x); //输出超类成员变量v
System.out.println("------3-----");
outinfo(); //调用子类的outinfo()方法
this.outinfo(); //调用子类的outinfo()方法
super.outinfo(); //调用父类的outinfo()方法
}
public static void main(String[] args) {
new Son().test();
}
}
子类Son运行结果:
Father构造方法被调用!
Son无参数构造方法被调用!
------1-----
哈哈哈哈!
Son
Father
------2-----
输出了Father类的public成员变量x!!!
输出了Father类的public成员变量x!!!
------3-----
Son的outinfo()方法被调用
Son的outinfo()方法被调用
Father的outinfo方法被调用
说明:次例子仅仅为了说明super的用法,实际在设计类的时候一般都尽可能私有(private)化。
通过上面的例子,下面总结一下super的用法:
第一、在子类构造方法中要调用父类的构造方法,用“super(参数列表)”的方式调用,参数不是必须的。同时还要注意的一点是:“super(参数列表)”这条语句只能用在子类构造方法体中的第一行。
第二、当子类方法中的局部变量或者子类的成员变量与父类成员变量同名时,也就是子类局部变量覆盖父类成员变量时,用“super.成员变量名”来引用父类成员变量。当然,如果父类的成员变量没有被覆盖,也可以用“super.成员变量名”来引用父类成员变量,不过这是不必要的。
第三、当子类的成员方法覆盖了父类的成员方法时,也就是子类和父类有完全相同的方法定义(但方法体可以不同),此时,用“super.方法名(参数列表)”的方式访问父类的方法。
this、super的用法也不过这些,只有理解了其中的原理,才不会跌入陷阱!
参考资料
Thinking in Java
Java2参考大全
class Super {
}class SubClass extends Super{
public void foo() {
System.out.println(this.getClass());
System.out.println(super.getClass());
}
}你们看看getClass() 是谁的方法。 是Object ,你如果想得到不同的结果就重写这个方法。但这个方法是不能重写的。所以无论你是supper supper supper 多少个继续 调用getClass 都是返回调用此方法的那个对象的运行时类
this:本类只是一个引用,没啥特别的,不要想复杂了
一个子类被创建,那这个子类对象在内存中的东西包括“新产生父类对象”加上“自己新定义的东西那一部分”,这样才是一个完整的子类对象。所以说每(创建)一个子类对象都(要创建)包含着一个父类对象。这个子类对象里面的父类对象跟你自己new一个父类对象的区别在哪里呢?本质没区别唯一区别就在:前者已经封装在子类里,它是子类的,别人不能用,而后者是独立的!所以你不能用子类的super去赋值于一个父类声明的引用。你应该自己去new一个独立的父类对象去完成赋值。而且由于引用应该是指能指向完整的一个“独立对象”,而super只是指向子类里的父类对象部分,所以super不能算是一个真正的引用,自然也不能拿它去赋值。
2
this引用和super(约等于)引用(子类内部的父类部分的地址)
this引用跟我用new出来的引用一样,你可以用他来赋值:class A {
void f(){
A a = this;
}
}这完全没问题。而super不行原因在1已经说了。
既然有了this指向自身(也就是说它也能指向其自身的父类部分),那为什么还需要super呢?
那是因为会碰到子类“重写父类成员”的情况,你用this.成员名,总会优先调用子类的,那么父类的总调用不到,于是super就是为了能调用父类被重写的成员而诞生。
(同时在方法体里(构造器里也一样)调用跟构造器同名的方法,都会被解读为成员方法而不是构造器)而且用法是:只能是构造器的第一句语句。——2个信息:1.只能在构造器中使用;2. 必须放在第一句
先从C++说起,这个能看到机器码。C++里,所有类都会有构造函数,没有的也会给你生成一个默认的(java一样),在语法层面这绝对是正确的,或者说逻辑上正确,实际呢?class Super
{
public:
//Super(){}
int aa;
};int main()
{
Super su;
su.aa = 1;
}赋值语句是为了让编译器生成这个类。反汇编,按道理该有个缺省构造函数,但是什么都没有,程序跑起来堆栈调整完就是
mov dword ptr [ebp-4],1
在某些地方,这种行为称为trivial,c++里大量存在,构造,拷贝等,决不浪费一行机器指令。
把那行注释去掉,反汇编,能看到call xxx ,push ebp,move ebp,esp 之类熟悉的调用,虽然什么都没干,但是的确跑到一个函数里转了一圈。如果以上还说的过去,那下面这行
int n=int(4)
从语法角度,生成一个int类对象,构造函数参数是4,怎么也该有个调用过程,反汇编,就一行,
mov dword ptr [ebp-8],4
语法和实现是两回事,不看汇编码,语法的完全一样,挑不出毛病;编译器做的过程却不对,结果是对的。回到java,指针是什么,引用是什么,语法角度能争论半天,其实都一样,都是指针。都是指向一个内存的代号。在看内存布局,SubClass实例里,Super内存在前,SubClass的在后,仅此而已,SubClass的引用和SubClass里Super部分的引用都是同一个地方,如果语法支持,这两个可以随便怎么转--虚函数除外。
剩下就是super到底是什么,其实只是个语法,java编译器根据它生成bytecode而已。
下面是我这里的foo,两个getClass完全一样,
public void foo();
0 getstatic java.lang.System.out : java.io.PrintStream [15]
3 aload_0 [this]
4 invokevirtual java.lang.Object.getClass() : java.lang.Class [21]
7 invokevirtual java.io.PrintStream.println(java.lang.Object) : void [27]
10 getstatic java.lang.System.out : java.io.PrintStream [15]
13 aload_0 [this]
14 invokespecial java.lang.Object.getClass() : java.lang.Class [21]
17 invokevirtual java.io.PrintStream.println(java.lang.Object) : void [27]
20 return
从实现层面解释,super和this指向同一个地方,getClass()得到的是"这个地址"所在类的名称,在此之前,class对象已经建好,所以查询出来都是SubClass的名称。
bytecode中有这行: local: this index: 0 type: SubClass
当我在Super和SubClass中都加入一个函数fo,并且SubClass.fo()中写super.fo()
1 invokespecial Super.fo() : void [34]
这回直接invoke了,完全就是一个reference的行为.可见是编译器在搞鬼,它正确的解释了语法中的super,却对我们造成了迷惑。所以我认为"super acts as a reference"这句话写的非常精确,不是reference,编译的时候让你以为是个reference
从jvm的实现的角度,我想楼主和我们能会有一个更清楚的认识
郑重推荐一本书: inside java virtual machine
1.首先,楼主的说法是对的,super不是引用,而是作为一个看似引用的行为。这点大家都说了,没有什么好解释的了。
2.我也有了一个困惑,就是楼主想得到一个super对象的引用。这时,就要明确一个问题,究竟有几个对象。也就是说只有SubClass这一个对象还是同时有Object,Super,SubClass三个对象。楼主的问题应该只有后者为真的情况下才有意义。那若此,就是说先创建父类的对象,并且要求父类对象与子类无关,完全放在一个独立的内存地址里的。然后,子类会隐含的拥有一个父类对象的引用。如果能搞到这个引用,问题不就解决了。但是这样在真正设计时会显得毫无意义,比如说你有一个“Fruit”的基类,和一个扩展它的Apple类。当你创建Apple类时,你的原意不是想得到一个关于Apple类的对象,它是作为Apple的对象而存在的。如果你想返回一个Fruit类的对象,你返回Apple对象的引用难道不能得到Fruit类的属性和行为吗?所以,得到一个完全独立的Fruit似乎就显得没有那么重要了。
super 表示对父类的某个构造器的调用……
this 当前对象
this()表示当前类对象调用;