面向对象(二)
this关键字:
//局部变量和成员变量存在二义性:
作用域链:{}形成作用域,作用域可以嵌套,内层作用域可以访问外层作用域的变量
/**
*当在作用域中访问一个变量var时,首先在自身作用域中找该变量var,如果自身作用域能找到,不继续向上一层找;
* 如果本层没有找到,继续向上一层找,如果该层没有,继续向其上一次找,查找的过程形成一条链,这个链称为作 * 用域链(scope chain)
*/
public class Student {
private String name; // 姓名
private int age; // 年龄
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 0){
System.out.println("非法的年龄");
return;
}
this.age = age;
}
public void showInfo(){
System.out.println("名字:" + name);
System.out.println("年龄:" + age);
}
}
public class Teat01 {
public static void main(String[] args) {
Student s1 = new Student();
System.out.println("s1 = " + s1);
s1.setName("大狗");
s1.setAge(20);
s1.showInfo();
Student s2 = new Student();
System.out.println("s2 = " + s2);
//当调用方法时,用什么对象调用,方法中的this就表示什么对象,也即当前对象
s2.setName("大狗");
s2.setAge(20);
s2.showInfo();
}
}
使用构造器还是setter方法
构造器和setter方法都可以给对象设置数据:
1.构造器,在创建对象的时候设置初始数据,只能初始化一次
2.setter方法,创建对象后再设置初始数据,可以设置多次
继承思想
继承在实战中的应用
1>两个类在现实中没有关系,但抽象的过程中发现他们有共同的特征和行为时,提取公共成员形成父类
2>现实生活中,他们有继承关系,反应到现实中就是 is a 关系,学生类 is a 人类
1.继承语法
在程序中,如果一个类想要继承另一个类,就需要使用extends关键字
//语法:
public class 子类名 extends 父类名{
}
//概念:
被继承的类,称之为父类
继承父类的类,称之为子类
父类:存放多个子类共同的字段和方法
子类:存放自己特有的/独有的字段和方法
总结:
Java类继承的特性:
【1】单根性,一个类只能有一个直接父类,但支持多重继承
【2】传递性,C extends B,B extends A,C也具备A的特性和行为
在Java中,存在4中访问修饰符,这4中修饰符用于控制Java中成员变量、成员方法、类、接口的访问权限
修饰符 | 类内部 | 同包子类、同包其他类 | 不同包子类 | 不同包其他类 |
---|---|---|---|---|
private | ✔ | ✘ | ✘ | ✘ |
默认 | ✔ | ✔ | ✘ | ✘ |
protected | ✔ | ✔ | ✔ | ✘ |
public | ✔ | ✔ | ✔ | ✔ |
private:私有的,只有本类可见
默认:没有关键字,包访问权限,同包可见。
protected:受保护的。(1)同包可见。(2)子类可见
public:公共的,都可见。
访问权限大小:private < 默认 < protected < public
1.继承操作
//父类代码:
public class Person {
private String name;
private int age;
public void rest(){
System.out.println(name + "正在休息...");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public Person(){} //无参构造器
public Person(String name,int age){ //有参构造器
setName(name);
setAge(age);
}
}
//子类代码:
public class Teacher extends Person{
private int level; //级别
//定义特有的字段和方法
public void teach(String aClass){
System.out.println(getName() + "正在授课:" + aClass);
}
public void setLevel(int level) {
this.level = level;
}
public int getLevel() {
return level;
}
public Teacher(){} //无参构造器
public Teacher(String name,int age,int level){ //有参构造器
setLevel(level);
setName(name); //继承父类
setAge(age); //继承父类
}
}
//测试类:
public class Test01Extends {
public static void main(String[] args) {
Teacher t1 = new Teacher("二狗",20,10);
t1.teach("java");
//继承父类的方法
t1.rest();
}
}
2.子类可以继承到父类那些成员
1.如果父类中的成员使用public和protected修饰,子类都能继承
2.如果父类和子类在同一个包中,使用缺省访问修饰的成员,此时子类可以继承到
3.如果父类中的成员使用private修饰,子类继承不到。private只能在本类中访问
4.父类的构造器,子类也不能继承,因为构造器必须和当前的类名相同
2.方法覆盖
1.方法覆盖操作
public class Bird {
public void fly(){
System.out.println("快乐的飞翔");
}
}
public class Ostrich extends Bird {
public void fly(){
System.out.println("扑哧扑哧,跑跑跑。。。");
}
}
public class Test01 {
public static void main(String[] args) {
Ostrich ostrich = new Ostrich();
ostrich.fly();
}
}
2.super关键字
在子类中某一个方法中需要去调用父类中被覆盖的方法,此时得使用super关键字
super关键字表示父类对象的意思。
super.方法名() 可以翻译成调用父类对象的(方法名)方法。
//例如:
public void doMaigre(){
super.Buddha();
super.doPilgrimage();
super.fight();
System.out.println(getName() + "又吃斋");
}
3.抽象方法和抽象类
1.抽象方法
抽象方法由abstract修饰方法,被abstract修饰的方法具有两个特征:
1.该方法没有方法体;
2.子类必须覆盖父类;
抽象方法的语法:
public abstract 返回类型 方法名(参数);
抽象方法的特点:
1.使用abstract修饰,没有方法体,留给子类覆盖
2.抽象方法必须定义在抽象类或接口中
2.抽象类
//使用abstract修饰的类,称为抽象类
抽象类的语法:
public abstract class 类名{
}
1.一般的抽象类以Abstract作为类名前缀,基本一眼就能看出是抽象类
2.如果一个类继承抽象父类,必须实现抽象父类中的所有抽象方法,除非该类也是抽象类
3.抽象类不能实例化,也就是创建对象,抽象类可以阻止实例化
抽象类的特点:
1.抽象类不能创建对象,调用没有方法体的抽象方法没有意义;
2.抽象类中可以同时拥有抽象方法和普通方法;
3.抽象类要有子类才有意义,子类必须覆盖父类的抽象方法,否则子类也得作为抽象类
//例如:父类代码
public abstract class AbstractGraph {
public abstract double getArea();
}
//子类代码:
public class Circle extends AbstractGraph{
private int r;
public double getArea(){
return r * r * 3.14;
}
public int getR() {
return r;
}
public void setR(int r) {
if(r < 0){
System.out.println("输入不合法");
}else{
this.r = r;
}
}
public Circle(int r) {
this.r = r;
}
public Circle() {
}
}
3.重写和实现
重写和实现的区别
重写:子类继承父类的方法时不能满足自身需要,子类可以选择重写父类的同名方法,这个同名的方法在父 类实现过的,只不过不能满足子类的需要,这个过程就是重写(override/overwrite)。
实现:子类继承父类的抽象方法时,必须重写父类的抽象方法,这个过程就是实现(implement),因为父类
中的方法是抽象的,没有方法体,父类从来就没有实现过这个方法。
//可以认为实现是一种特殊的重写
4.Object类和常用方法
Object 本身表示对象的意思,是Java中的根类,要么是一个类的直接父类,要么就是一个类的间接父类
class A{} 其实等价于 class A extends Object{}
因为所有类都是Object类的子类,所有类的对象都可以调用 Object 类中的方法
1.equals
//在Object类中的equals方法和“ == ”符号相同都是比较对象是否是同一个的存储地址。
//每个类都应该覆盖equals方法去比较我们关心的数据,而不是内存地址。
例如:
public class Test {
public static void main(String[] args) {
Person t1 = new Person("阿古",20);
Person t2 = new Person("阿古",20);
//比较t1和t2的内存地址是否相同
boolean ret1 = t1 == t2;
boolean ret2 = t1.equals(t2);
System.out.println(ret1);//false
System.out.println(ret2);//false
}
}
2.String toString()
String toString()表示把对象中的字段信息转换为字符串格式
//默认情况下打印的是对象的hashCode值,但是我们更关心对象中字段存储的数据。
//官方建议:应该每个类都应该覆盖toString返回我们关心的数据,
如:
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
IDEA快捷键:::
Alt + Insert
3.== 符号到底比较的是什么:
1.比较基本数据类型:比较两个值是否相等
2.比较对象数据类型:比较两个对象是否是同一块内存空间
//每一次使用new关键字,都表示在堆中创建一块新的内存空间。