public class People {
String name;
int age;
void say() {
System.out.println("I am" + name + "age:" + age);
}
}
public class Test {
public static void main(String[] args) {
People p = new People();
p.name="tom";
p.age=23;
}
}
对象内存图解:
对象在堆内存中占据的是一片连续的空间,栈中的引用只要知道它的首地址值就可以找到这个对象,在堆中生成的变量具有默认值,类中的方法存储在方法区。
成员变量和局部变量的区别:
成员变量定义在类中;局部变量定义在方法中
成员变量存储在堆内存的对象中;局部变量存储在栈内存的方法中
成员变量随对象的消亡而消亡;局部变量随方法的消亡而消亡
成员变量有默认值;局部变量没有,初始化后才可以使用
匿名对象:
new People().name="Jerry";
new People().age=12;
当执行第一条语句时,同样会在堆中生成一个对象,将name赋值为Jerry,当第一行执行完毕,因为没有引用指向,所以对象会被当垃圾回收掉,第二条语句同理。
类的构造方法:如果一个类中无任何构造方法,编译器会自动创建一个不带参数的默认构造方法;如果类中都不是无参的构造方法,编译器不会为类设置一个默认的无参构造方法。当对象一生成构造方法就会执行,构造方法会进栈,其中会有参数,并将参数值赋值给对象中的成员变量,当对象生成完毕,构造方法出栈。
构造函数是可以相互调用的,用this关键字
People(String name) {
this.name = name;
}
People(String name, int age) {
this(name);
this.age = age;
}
对象调用的方法中都有this引用指向着该对象,第二个构造方法会将name参数传递给第一个构造方法,第一个构造方法会将值传递给类中的成员变量。然后第一个构造方法出栈,第二个构造方法将age参数传递给类中的age变量,第二个方法出栈。必须将this放在第一句。
一般函数是不能调用构造方法的,因为一般函数是在类生成以后才调用的,构造方法是可以调用一般方法的。子类的构造函数中的第一行都有一句隐士语句super();默认调用的的是无参构造方法,主要是用来初始化父类,便于子类继承。如果子类的构造函数中第一行是this(),就没有super(),因为this()和super()是用来初始化的,只能写在第一行,this()中是有super()的。
1、我们可以把JAVA中的类分为以下三种:
类:使用class定义且不含有抽象方法的类。
抽象类:使用abstractclass定义的类,它可以含有,也可以不含有抽象方法。
接口:使用interface定义的类。
在这三种类型之间存在下面的继承规律:
类可以继承(extends)类,可以继承(extends)抽象类,可以继承(implements)接口。
抽象类可以继承(extends)类,可以继承(extends)抽象类,可以继承(implements)接口。
接口只能继承(extends)接口。
2、继承(inheritance)
Java的继承具有单继承的特点,每个子类只能有一个直接父类。
构造器是不能被继承的。子类可以继承超类的任何方法。
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。
当调用子类构造函数来初始化子类对象的时候,父类的构造函数总是在子类的构造函数之前执行,然后执行父类的构造时,又会追溯到其父类的构造函数…,因此,创建任何java对象时,最先执行的总是java.long.Object这个累的构造函数。
父类和子类有同名的变量时,调用子类的变量,否则,调用父类的对象。如果想调用父类的同名变量,用super即可,super和this不一样,代表的是父类的内存空间,并不是一个对象,不可以直接输出super。
3、封装(encapsulation)
类使得数据和对数据的操作集成在一起,从而对使用该类的其他人来说,可以不管它的实现方法,而只管用它的功能,从而实现所谓的信息隐藏。 封装隐藏了类的内部实现机制,从而可以在不影响使用者的前提下改变类的内部结构,同时保护了数据。
4、多态(polymorphism)
方法的重写、重载与动态连接构成多态性。Java之所以引入多态的概念,原因之一是它在类的继承问题上和C++不同,后者允许多继承,这确实给其带来的非常强大的功能 ,但是复杂的继承关系也给C++开发者带来了更大的麻烦,为了规避风险,Java只允许单继承,派生类与基类间有IS-A的关系(即“猫”is a“动物”)。这样做虽然保证了继承关系的简单明了,但是势必在功能上有很大的限制,所以,Java引入了多态性的概念以弥补这点的不足,此外,抽象类和接口也是解决单继承规定限制的重要手段。同时,多态也是面向对象编程的精髓所在。例如Animal a=new Cat();
,只能使用父类中已有的方法,不能操作子类特有的方法,当想使用子类的特有内容时,用强制转换Cat c=(Cat)a;
,如果new的是Animal,Dog不能强制转换,可以先判断一下
if (a instanceof Cat) {
Cat c = (Cat) a;
c.fun();
} else if (a instanceof Dog) {
Dog d = (Dog) a;
d.fun();
}
多态又分为设计时多态和运行时多态,例如重载又被称为设计时多态,而对于覆盖或继承的方法,JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态。总而言之,面向对象的设计的典型特点就是继承,封装和多态,这些特点也是面向对象之所以能如此盛行的关键所在。
当父类和子类有相同的变量时:
Father f = new Son();
System.out.print(f.name);
输出的会是父类的name,内存中会有两个name,但f会先查找本类的变量。
当子类和父类有同名的成员方法时:
会调用子类的方法,因为方法有个特性是重写覆盖。
当子类和父类有同名的静态方法时:
会调用父类的方法,因为静态方法只与类有关,正规调用是类直接调用。
对于多态,可以总结它为:
一、使用父类类型的引用指向子类的对象;该引用只能调用父类中定义的方法和变量;
二、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)
三、变量不能被重写(覆盖),”重写“的概念只针对方法。
关于内部类的两篇文章:
http://www.cnblogs.com/nerxious/archive/2013/01/24/2875649.html
http://www.cnblogs.com/mengdd/archive/2013/02/08/2909307.html