子类对象是包含整个父类对象仍是仅仅拥有父类对象的引用?
子类对象是包含整个父类对象还是仅仅拥有父类对象的引用??
子类为C,父类为F;
---------------------------------------------------------
C实例化之前会先实例化F
那么
最后得到的C对象是包含了F对象?
还是
仅仅在C对象中包含了F对象的引用??如果是这种情况,是不是说:实例化一个子类对象,会把他所有的父类实例化并且保存下来,这样是不是会很浪费内存,毕竟好多类是有很多父类的。
问题应该也可以等同于
当通过C对象调用没有被覆写的方法时,是直接调用了C对象中的方法?
还是通过引用调用了F对象的方法?
------解决思路----------------------
C实例化之前会先实例化F 意思是说创建子类对象之前先创建父类对象吗?
创建子类不会创建父类对象吧!详情http://liujinpan75.iteye.com/blog/785136
------解决思路----------------------
子类为C,父类为F;
---------------------------------------------------------
C实例化之前会先实例化F
那么
最后得到的C对象是包含了F对象?
还是
仅仅在C对象中包含了F对象的引用??如果是这种情况,是不是说:实例化一个子类对象,会把他所有的父类实例化并且保存下来,这样是不是会很浪费内存,毕竟好多类是有很多父类的。
问题应该也可以等同于
当通过C对象调用没有被覆写的方法时,是直接调用了C对象中的方法?
还是通过引用调用了F对象的方法?
=====================================================================
首先,他们是继承关系!这里的继承和实例对象是两个维度,可以理解为代码的复用。所以子类实例化并不会实例化一个父类,而是会初始化父类,原因很简单他要复用父类的属性和方法。
第二,你所说的方法调用那么要从字节码class深入理解,你可以看一下生成的class文件,如果子类没有重写父类的方法,那么是不会包含父类的方法信息(就是说子类没有父类的方法代码),那么他是怎么调用的呢?很简单,字节码里边生成的时候有个所属父类索引信息,jvm执行的时候就是通过这些属性执行方法流程的,当然这个在编写java程序时不可见,楼主可以u看看jvm的深入理解便会明白很多。
------解决思路----------------------
运行结果:
1 FathersFather类变量初始化
2 Father类变量初始化
3 Child类变量初始化
4 FathersFather实例变量初始化
5 FathersFather构造器调用
6 Father实例变量初始化
7 Father构造器调用
8 Child实例变量初始化
9 Child构造器调用
=========================
结论:子类实例化必然伴随父类实例化,也就是说产生了父类的对象。但是父类对象的引用不可传递。也就是说只能通过super关键字从子类中访问父类的方法、字段。构造器等,当然,是在权限许可的情况下。但是无法将super赋值给新的引用变量。
------解决思路----------------------
没错~你的理解是对的。
------解决思路----------------------
父类初始化是肯定的,同时父类的构造函数也会被调用,这就相当于实例化了父类,只是没有将其赋给一个引用变量而已。
------解决思路----------------------
1.对像和类是两个维度的东西,您以可将子类和父类看成完全不同的两个类,所以它们的实例化没有任何相干性。
2.子类的实例和父类的实例之前没有任合关系。
3.子类的对像只是和你类拥有相同的父类暴露出来的函数、常量值、成员变量名及初始化值,仅此而已。
------解决思路----------------------
对象的实例化和初始化是两个概念
对象初始化的时候如果发现父类没有被初始化,就会先初始化父类,依次类推,但是如果父类是接口则不会去初始化父类
类的初始化是由类被主动使用导致的,new是一种,Class.forName()是一种,还有就是调用一个类的方法、属性或延迟的常量(就像下面的例子)
------解决思路----------------------
大多数类都有默认的构造方法,子类实例化时会先调用父类的构造方法。
因为是继承,所以子类继承了父类除构造方法以外的所有方法,实例化谁就调用谁里面的方法,也就是new后面的那部分。
------解决思路----------------------
从实现上来说,父子进程应该位于一个同样的内存起始地址,只不过对这片内存地址的引用和解释依赖于前面的类型,因为Java依赖于JVM,所以这个地方你可以借用下C++看下,OO的实现机制大体都是一样的,父子进程没道理布局在不同的内存区域上,因为这样在runtime时,势必降低效率
你看下C++的实现
#include <iostream>
using namespace std;
class A{
public:
A(){
this->value = 2;
printf("Parent %p %p\n ",this, &(this->value));
}
public:
int value;
};
class B: public A{
public:
B(){
this->value = 0;
this->mChildValue = 1;
printf("Child %p %p\n\n", this, &(this->mChildValue));
}
private:
int mChildValue;
};
int main(int argc, char *argv[])
{
B b;
return 0;
}
Parent 0x7fff5fbffc88 0x7fff5fbffc88
Child 0x7fff5fbffc88 0x7fff5fbffc8c
0x7fff5fbffc88 这个是父子进程的内存首地址,2者是一样的,构造的时候先构造了父类,接着在后面的内存区上构建子类 对应的java对象这个构建在堆上 0x7fff5fbffc8c 这个由于子类自己加了一个4字节的成员变量,可以看到子类和父类的field的偏移量就是这个4字节的对象
------解决思路----------------------
打错了 父子对象
子类为C,父类为F;
---------------------------------------------------------
C实例化之前会先实例化F
那么
最后得到的C对象是包含了F对象?
还是
仅仅在C对象中包含了F对象的引用??如果是这种情况,是不是说:实例化一个子类对象,会把他所有的父类实例化并且保存下来,这样是不是会很浪费内存,毕竟好多类是有很多父类的。
问题应该也可以等同于
当通过C对象调用没有被覆写的方法时,是直接调用了C对象中的方法?
还是通过引用调用了F对象的方法?
------解决思路----------------------
C实例化之前会先实例化F 意思是说创建子类对象之前先创建父类对象吗?
创建子类不会创建父类对象吧!详情http://liujinpan75.iteye.com/blog/785136
------解决思路----------------------
子类为C,父类为F;
---------------------------------------------------------
C实例化之前会先实例化F
那么
最后得到的C对象是包含了F对象?
还是
仅仅在C对象中包含了F对象的引用??如果是这种情况,是不是说:实例化一个子类对象,会把他所有的父类实例化并且保存下来,这样是不是会很浪费内存,毕竟好多类是有很多父类的。
问题应该也可以等同于
当通过C对象调用没有被覆写的方法时,是直接调用了C对象中的方法?
还是通过引用调用了F对象的方法?
=====================================================================
首先,他们是继承关系!这里的继承和实例对象是两个维度,可以理解为代码的复用。所以子类实例化并不会实例化一个父类,而是会初始化父类,原因很简单他要复用父类的属性和方法。
第二,你所说的方法调用那么要从字节码class深入理解,你可以看一下生成的class文件,如果子类没有重写父类的方法,那么是不会包含父类的方法信息(就是说子类没有父类的方法代码),那么他是怎么调用的呢?很简单,字节码里边生成的时候有个所属父类索引信息,jvm执行的时候就是通过这些属性执行方法流程的,当然这个在编写java程序时不可见,楼主可以u看看jvm的深入理解便会明白很多。
------解决思路----------------------
ackage extendtest;
/**
*
* @author Administrator
*/
public class Test {
public static int Number=1;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Child ppa=new Child();
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools
------解决思路----------------------
Templates
* and open the template in the editor.
*/
package extendtest;
/**
*
* @author FathersFatherdministrator
*/
public class FathersFather {
private String i;
private static String s;
{
this.i="FathersFather";
System.out.println(Test.Number+++" "+i+"实例变量初始化");
}
static {
s="FathersFather";
System.out.println(Test.Number+++" "+s+"类变量初始化");
}
public FathersFather() {
System.out.println(Test.Number+++" "+"FathersFather构造器调用");
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools
------解决思路----------------------
Templates
* and open the template in the editor.
*/
package extendtest;
/**
*
* @author Administrator
*/
public class Father extends FathersFather{
private String i;
private static String s;
{
this.i="Father";
System.out.println(Test.Number+++" "+i+"实例变量初始化");
}
static {
s="Father";
System.out.println(Test.Number+++" "+s+"类变量初始化");
}
public Father() {
System.out.println(Test.Number+++" "+"Father构造器调用");
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools
------解决思路----------------------
Templates
* and open the template in the editor.
*/
package extendtest;
/**
*
* @author Administrator
*/
public class Child extends Father{
private String i;
private static String s;
{
this.i="Child";
System.out.println(Test.Number+++" "+i+"实例变量初始化");
}
static {
s="Child";
System.out.println(Test.Number+++" "+s+"类变量初始化");
}
public Child() {
System.out.println(Test.Number+++" "+"Child构造器调用");
}
}
运行结果:
1 FathersFather类变量初始化
2 Father类变量初始化
3 Child类变量初始化
4 FathersFather实例变量初始化
5 FathersFather构造器调用
6 Father实例变量初始化
7 Father构造器调用
8 Child实例变量初始化
9 Child构造器调用
=========================
结论:子类实例化必然伴随父类实例化,也就是说产生了父类的对象。但是父类对象的引用不可传递。也就是说只能通过super关键字从子类中访问父类的方法、字段。构造器等,当然,是在权限许可的情况下。但是无法将super赋值给新的引用变量。
------解决思路----------------------
没错~你的理解是对的。
------解决思路----------------------
父类初始化是肯定的,同时父类的构造函数也会被调用,这就相当于实例化了父类,只是没有将其赋给一个引用变量而已。
------解决思路----------------------
1.对像和类是两个维度的东西,您以可将子类和父类看成完全不同的两个类,所以它们的实例化没有任何相干性。
2.子类的实例和父类的实例之前没有任合关系。
3.子类的对像只是和你类拥有相同的父类暴露出来的函数、常量值、成员变量名及初始化值,仅此而已。
------解决思路----------------------
对象的实例化和初始化是两个概念
对象初始化的时候如果发现父类没有被初始化,就会先初始化父类,依次类推,但是如果父类是接口则不会去初始化父类
类的初始化是由类被主动使用导致的,new是一种,Class.forName()是一种,还有就是调用一个类的方法、属性或延迟的常量(就像下面的例子)
public class InitialTest {
public static void main(String[] args) {
Entity e = new Entity();
Good g = e.CONST;//此处注释就不会打印"Good initial!"
}
static class Entity implements Bean {
@Override
public void execute() {
// TODO Auto-generated method stub
}
static{
System.out.println("Entity initial!");
}
}
interface Bean {
Good CONST = new Good();
void execute();
}
static class Good {
static {
System.out.println("Good initial!");
}
}
}
------解决思路----------------------
大多数类都有默认的构造方法,子类实例化时会先调用父类的构造方法。
因为是继承,所以子类继承了父类除构造方法以外的所有方法,实例化谁就调用谁里面的方法,也就是new后面的那部分。
------解决思路----------------------
从实现上来说,父子进程应该位于一个同样的内存起始地址,只不过对这片内存地址的引用和解释依赖于前面的类型,因为Java依赖于JVM,所以这个地方你可以借用下C++看下,OO的实现机制大体都是一样的,父子进程没道理布局在不同的内存区域上,因为这样在runtime时,势必降低效率
你看下C++的实现
#include <iostream>
using namespace std;
class A{
public:
A(){
this->value = 2;
printf("Parent %p %p\n ",this, &(this->value));
}
public:
int value;
};
class B: public A{
public:
B(){
this->value = 0;
this->mChildValue = 1;
printf("Child %p %p\n\n", this, &(this->mChildValue));
}
private:
int mChildValue;
};
int main(int argc, char *argv[])
{
B b;
return 0;
}
Parent 0x7fff5fbffc88 0x7fff5fbffc88
Child 0x7fff5fbffc88 0x7fff5fbffc8c
0x7fff5fbffc88 这个是父子进程的内存首地址,2者是一样的,构造的时候先构造了父类,接着在后面的内存区上构建子类 对应的java对象这个构建在堆上 0x7fff5fbffc8c 这个由于子类自己加了一个4字节的成员变量,可以看到子类和父类的field的偏移量就是这个4字节的对象
------解决思路----------------------
打错了 父子对象