1. 类和对象
类可以认为是自定义的数据类型,.类用于描述某一类对象的共同特征,对象是类的具体存在.
java中的对象及其属性数据是存放在堆(heap)内存中的,而引用变量则是存放在栈内存中的.
Person p = new Person();
系统会生成两个实体,一个是引用变量p,一个是Person对象.栈内存中的引用变量p指向堆内存中的Person对象,变量p只是存储了一个地址值,本身不包含任何实际数据.堆内存中的数据不允许直接访问,只能通过该对象的引用去访问该对象.
Person p1 = p;
将p变量赋给p1,也就是将p变量保存的地址值赋给p1.这样p1也指向了堆内存中的同一个对象,这样不管是通过p还是p1访问对象的属性和方法,结果都是访问同一个对象的属性和方法,返回的结果都是一样的.也就是说堆内存中的对象可以有多个引用.
p = null;
当堆内存中的某个对象没有引用执行它时,程序将无法再访问到这个对象,这个对象也就是无用的了,垃圾回收机制将回收这个对象,释放该对象所占用的内存空间.因此,如果需要垃圾回收机制回收某个对象,只要切断该对象的所有引用即可,也就是将相关的引用赋为null.
内存示意图:
2. 面向对象的特征
1. 封装
对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问.类似客观世界中的属性都是隐藏在对象内部的,外部无法直接操作和修改.良好的封装是通过对外暴露足够的方法来操作和访问类的内部信息.
访问控制级别从private到public逐次变大
2. 继承
1. java不支持多重继承,每个子类只有一个直接父类
2. Object类是一切类的父类
3. 子类继承不能继承父类的私有的成员变量和成员方法.
在抽象类中定义了私有的成员方法或变量,子类不能访问到父类的私有成员,所以子类中重写父类的私有方法,实际上是新建了一个方法;在接口定义中的成员是不能为私有的,否则编译会报错,因为接口是用来公开的,私有的变量和方法不能被继承或实现.
4. 覆盖和被覆盖的方法必须同是实例方法或同时类方法
5. 子类中的变量可以覆盖父类中同名的变量,但并不是覆盖,而只是屏蔽,父类的变量并未改变
6. 调用子类构造方法之前,系统会先调用父类的构造方法,如果有多个父类,则从上到下依次调用
7. 内存机制中,父类和子类是占用同一块内存空间的,只是子类在父类的基础上增加自己的属性和方法.
8. 在子类中可通过super访问父类中的成员.
9. 系统创建某个类的对象时,系统总会隐式地创建该类父类的对象.在子类方法中,super指向该方法调用者的子类对象的父类对象.
代码清单: 继承
abstract class A {
int i=1;
public void printI() {
System.out.println("i="+i);
}
}
public class B extends A{
int i=2;
public void printI() {
super.printI();
}
public static void main(String[] args) {
B b=new B();
b.printI(); //i=1;
}
}
3. 多态
1. 相同类型的变量,执行同一个方法时呈现出不同的行为特征,就是多态.多态发生在编译时类型和运行时类型不一致时.
2. 引用类型在编译阶段只能调用其编译时类型所具有的方法,运行时则执行它运行时类型所具有的方法
3. 引用变量只能调用声明该变量的所用的类包含的方法,通过引用变量只能访问到编译时类所定义的属性.
例如 BaseClass bsc = new SubClass()通过变量bsc只能调用BaseClass所定义的方法,而不能访问sub(),所以bsc.sub()会编译不通过.可以通过bsc访问test(),但运行时调用的是SubClass类的方法.通过bsc访问的属性book是BaseClass的属性.
class BaseClass {
public int book = 1;
public void base() {
System.out.println("父类的普通方法");
}
public void test() {
System.out.println("父类被覆盖的方法");
}
}
public class SubClass extends BaseClass{
public String book = "JAVA";
public void test() {
System.out.println("子类覆盖父类的方法");
}
public void sub() {
System.out.println("子类的普通方法");
}
public static void main(String[] args) {
System.out.println("=======BaseClass bc = new BaseClass();=======");
BaseClass bc = new BaseClass();
System.out.println(bc.book);
bc.test();
bc.base();
System.out.println("=======SubClass sc = new SubClass();=======");
SubClass sc = new SubClass();
System.out.println(sc.book);
sc.test();
sc.base();
System.out.println("=======BaseClass bsc = new SubClass();=======");
BaseClass bsc = new SubClass();// 编译时类型和运行时类型不一致时,发生多态
System.out.println(bsc.book);//打印:1,对象的属性不具有多态性,只能访问编译时类型中的属性
bsc.test();//子类覆盖父类的方法,运行时调用的是运行时类型所定义的方法.
bsc.base();//父类的普通方法
//bsc.sub();// 只能访问编译时类型中所定义的方法
}
}