Copyright @BJTShang
看上去:是用于区分局部变量和成员变量同名的情况;为何可以解决这个问题?
class Person{
Person(String name){
this.name = name;
}
public static void main(String[] agrs){
new Person("BJTShang");
}
}
this 代表本类对象,更具体:代表本方法所属类的对象的引用;
class Person{
private int age;
Person(int age){
this.age = age;
}
public boolean compare(Person p){
return this.age==p.age;//这里this代表使用这个方法的p1对象引用,局部变量p代表传入的p2对象引用
}
public void main(String[] agrs){
Person p1 = new Person(20);
Person p2 = new Person(25);
System.out.println(p1.compare(p2));
}
}
this的一个特殊应用:构造方法的相互调用,且必须放在构造方法的第一行(防止该构造方法后续的语句修改调用的构造函数中的初始化参数)
class Person{
String name;
private age;
Person(){
}
Person(String name){
this.name = name;
}
Person(String name,int age){
this(name);//相当于p1(name)调用同类的另一个构造方法
this();//调用空参数的构造方法
this.age = age;
}
public static void main(String agrs){
Person p1 = new Person("BJTShang",25);
}
}
另外,this还可以作为方法的返回值使用,典型应用在get()方法中。
Person p1 = new Person("BJTShang",20);
这句对象初始化语句在内存中的过程(不考虑在方法区中的数据):
* 因为new用到了Person.class,所以会找到Person.class文件加载在内存中;
* 如果有的话,执行类中的static{}静态代码块,对类进行初始化;
* 在堆内存中开辟空间,分配内存地址;
* 在对内存中建立对象的特有属性(未被static修饰的,被static修饰的属性放入方法区/共享区/数据区),并进行默认初始化,例如String name=null;int age=0;
* 对属性进行显式初始化;例如在类中已经定义的String name=”BJTShang”;
* 对对象进行{}构造代码块初始化;
* 对对象进行对应的构造方法初始化;
* 将内存地址赋值给栈内存中的引用变量p1;
一个类在内存中只存在一个对象
* 禁止其他程序建立该类对象;(私有化构造方法)
* 避免其他程序建立对象,在本类中自定义一个对象;(在类中创建一个本类对象)
* 对外提供一些访问方式;(提供一个方法,可以得到该对象)
class Single{
private Single(){}
private static Single s= new Single();
public static Single getInstance(){
return s;
}
}
class SingleSet{
public static void main(String[] agrs){
Single s1 = Single.getInstance();
}
}
重载:只看参数列表不一样;
重写:子父类方法一模一样;
继承的优点:提高复用性,引入了多态的概念;
继承的缺点:打破了封装性。
多个类中出现相同功能,功能主体不同(方法声明相同,方法体不同);可以向上抽取功能定义,标识为抽象方法(没有方法体);该抽象方法必须存在抽象类中;
简单理解为:如果抽象类中的所有方法都是抽象时,可以通过接口的形式来表示(一种特殊的抽象类,比抽象类更抽象!);
接口中的常见的成员都有固定修饰符(没有默认被补上);
接口中成员都是public的
interface Inter{
public static final int NUM = 1;
public abstract void show();
}
class Test implements Inter{
}
interface C extends B,A
abstract class Student{
abstract void study();
void sleep(){
System.out.println("sleep");
}
//不是子类的共性,使用接口来实现abstract void smoke();
}
interface Smoking{
void smoke();
}
class Zhangsan extends Student implements Smoking{
void study(){}
public void smoke(){}
}
/**不属于Student类的teacherA也可以实现Smoking的接口,扩展teacher的功能, 这种Smoking功能,不是所有Teacher类都有的*/
class teacherA extends Teacher implements Smoking{
...
public void smoke(){}
}
要有继承,要有重写,要有父类引用指向子类对象;
1. 多态的体现
1. 父类的引用指向了自己的子类对象;
2. 父类的引用也可以接收自己的子类对象(传递参数);
2. 多态的前提
1. 类与类之间需要有关系:继承,实现;
2. 存在方法覆盖,需要使用这个覆盖的方法;
3. 多态的好处
1. 提高了程序的扩展性;
4. 多态的应用
class Cat extends Animal{
...
}
Animal a = new Cat();//向上转型
a.eat();
//a.catchMouse();--> 将父类引用转换成子类类型
Cat c = (Cat)a;//向下转型
c.catchMouse();
在多态中,成员方法的特点:
1. 在编译时期:引用所属的类中是否有调用的方法:如果有,编译通过,如果没有(通常会错误使用子类中的方法),编译失败;
2. 在运行时期:引用指向子类创建的对象,通过该对象的引用访问方法,因此,如果父方法中的方法被子方法重写,再使用父类引用调用此方法,将执行的是子类中重新定义的方法;
3. (面试)但是如果父类的方法是static的,则没有此特性,因为只有非静态的方法才可以被重写:在类初始化时,静态方法就已经存在于方法区的静态区(内存)中了,也就是说该方法已经被该类静态绑定,相对的是非静态方法被(例如this关键字)动态绑定;
class Father{
void method1(){//没有返回值的通常叫做工具类方法
}
void method2(){
}
}
class Son extends Father{
void method1(){//重写父类中的method1()方法
}
void method3(){
}
public static void main(String[] agrs){
Father f = new Son();
f.method1();//执行的是被子类重写的方法
f.method2();
//f.method3();编译无法通过!因为在编译时,不创建对象,此时引用型变量f不指向子类对象,当然无法使用子类中才有的方法!
}
}
(面试)在多态中,成员变量的特点:(与方法不同!因为子类变量不是重写父类变量,而是在实例化时,父类和子类的同名变量同时存在于堆内存中?)
* 无论编译还是运行,都参考引用变量所属的类中的成员变量;
原则:静态参考类去确定:静态绑定;非静态参考对象去确定:动态绑定!
为何要有内部类?要想访问外部类成员,定义方法不就行了么?继承不也可以么?为啥要有内部类?
观点:内部类“实现”了Java多重继承?每个内部类都可以独立继承一个接口(或者具体的类)来实现;
不能被private和static修饰,且必须在局部先创建此类对象,才能使用:
* 成员内部类才可以被private,static修饰;
* 局部内部类不可以被private,static修饰,因为private和static都是成员修饰符!;
* 局部内部类可以直接访问外部类的成员,因为它持有一个外部类的引用;但是不可以访问它所在局部中的变量,只能访问被final修饰的局部变量:
class Outer{
int x = 3;
void outermethod(){
//int y = 4;局部内部类需要访问局部变量,需要声明为final
final y = 4;
class Inner{
void inner method(){
System.out.println(x+" "+y);//x前省略Outer.this.x
}
}
}
}
内部类必须是继承一个类,或者实现一个接口;为何?因为要想实例化这个没有名字的类,只能先去实例化它的父类;被创建的对象,带有内容(对象体)–这个内容是为了实现被继承的类或者接口
class Outer{
int x = 4;
class Inner{
void show(){
System.out.println("x="+x);
}
}
void function(){
new Inner().show();
}
public static void main(String[] agrs){
new Outer().function();
}
}
使用匿名内部类实现:
* new 父类或者接口(){定义子类的内容};
* 匿名内部类就是以这个匿名子类对象,而且这个对象有点胖,可以理解为带内容的对象;
* 匿名内部类中的方法不要超过三个;
abstract class FatherClass{//需要有继承
abstract void show();
}
class Outer{
int x = 4;
void method(){
new FatherClass(){//通过实例化基类对象,获得匿名内部类的内容
void show(){
System.out.println("x="+x);
}
}.show();
}
public static void main(String[] agrs){
new Outer();
}
(面试)