【原】Java学习笔记017 - 面向对象

 package cn.temptation;

 public class Sample01 {
public static void main(String[] args) {
// 继承关系中的private访问权限:子类只能访问父类中的非私有的成员
}
} //// 父类
//class Father {
// // 成员变量
// // 子类从父类继承时,父类的private的成员变量(私有的成员变量)对于子类来说是无法访问的
// private String secret = "秘密";
// // 子类从父类继承时,父类的public的成员变量(公有的成员变量)对于子类来说是可以访问的
// public String info = "信息";
//
// // 成员方法
// // 子类从父类继承时,父类的private的成员方法(私有的成员方法)对于子类来说是无法访问的
// private void showByFatherPrivate() {
// System.out.println("这是Father类的私有成员方法");
// }
//
// // 子类从父类继承时,父类的public的成员方法(公有的成员方法)对于子类来说是可以访问的
// public void showByFatherPublic() {
// System.out.println("这是Father类的公有成员方法");
// }
//}
//
//// 子类
//class Baby extends Father {
// // 成员方法
// public void showByBaby() {
// System.out.println("这是Baby的成员方法");
// }
//
// public void use() {
// System.out.println(info);
// // 语法错误:The field Father.secret is not visible
//// System.out.println(secret);
//
// showByFatherPublic();
// // 语法错误:The method showByFatherPrivate() from the type Father is not visible
//// showByFatherPrivate();
// showByBaby();
// }
//}
 package cn.temptation;

 public class Sample02 {
public static void main(String[] args) {
// 【继承使用的场合:在描述类与类之间是一种"is a(an)"的关系时,推荐使用继承】
// 使用时,千万不要为了继承而继承 TestC testC = new TestC();
testC.method1();
testC.method3();
// 因为滥用继承,这时TestC对象多出了method2这个行为的
testC.method2();
}
} class TestA {
public void method1() {
System.out.println("method1");
} public void method2() {
System.out.println("method2");
}
} //class TestB {
// public void method2() {
// System.out.println("method2");
// }
//
// public void method3() {
// System.out.println("method3");
// }
//} // 出于为了节省TestB中代码的考虑,也就是为了不想写method2方法,选择从TestA继承
class TestB extends TestA{
public void method3() {
System.out.println("method3");
}
} //class TestC {
// public void method1() {
// System.out.println("method1");
// }
//
// public void method3() {
// System.out.println("method3");
// }
//} // 出于为了节省TestC中代码的考虑,也就是为了不想写method1方法,选择从TestB继承
class TestC extends TestB { }
 package cn.temptation;

 public class Sample03 {
public static void main(String[] args) {
// 需求:苹果是一种水果,颜色是红色的,吃起来是甜的,可以做手机;
// 香蕉也是一种水果,颜色是黄色的,吃起来是软的,可以打架 Apple apple = new Apple();
apple.setName("苹果");
apple.setColor("红色");
System.out.println("水果的名称为:" + apple.getName() + ",颜色为:" + apple.getColor());
apple.taste("甜");
apple.makePhone(); Banana banana = new Banana();
banana.setName("香蕉");
banana.setColor("黄色");
System.out.println("水果的名称为:" + banana.getName() + ",颜色为:" + banana.getColor());
banana.taste("软");
banana.fight();
}
} // 水果类(父类)
class Fruit {
// 成员变量
// 名字
private String name;
// 颜色
private String color; // 成员方法
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getColor() {
return color;
} public void setColor(String color) {
this.color = color;
} // 自定义的成员方法
public void taste(String feeling) {
System.out.println("味道是:" + feeling + "的!");
}
} // 苹果类(子类)
class Apple extends Fruit {
// 成员变量 // 成员方法
public void makePhone() {
System.out.println("做手机");
}
} // 香蕉类(子类)
class Banana extends Fruit {
// 成员变量 // 成员方法
public void fight() {
System.out.println("用来打架");
}
}
 package cn.temptation;

 public class Sample04 {
public static void main(String[] args) {
// 类的常见结构(写法约定:从上向下)
// 成员变量
// 静态代码块
// 构造代码块
// 无参构造函数
// 有参构造函数
// get/set方法
// 自定义成员方法 // 说到继承,自然考虑形成继承关系的两个类的结构间互相关系 // 对于成员变量而言
// 1、子类的成员变量 和 父类的成员变量名字不同,只要父类的成员变量非私有的,在子类中就可以访问
// 2、子类的成员变量 和 父类的成员变量名字相同,只要父类的成员变量非私有的,子类的成员方法访问同名的成员变量时,依旧遵循"就近原则"
// 调用子类的成员方法有两种:均遵循"就近原则"
// 子类自己的成员方法访问子类自己有且父类也有的成员变量
// 子类继承自父类的成员方法访问子类自己有且父类也有的成员变量
// 3、子类没有而父类有的成员变量,只要父类的成员变量非私有的,在子类中就可以访问 // 思考:继承关系的子类和父类,变量的访问规则是什么?
// 对于子类的成员方法中的语句来说,最近的是成员方法的局部变量(如果局部变量存在的话)
// 如果局部变量不存在,则在子类的成员变量中找(如果子类的成员变量存在的话)
// 如果子类的成员变量不存在,则在父类的非私有的成员变量中找(如果父类的非私有的成员变量存在的话)
// 如果父类的非私有的成员变量不存在,则语法出错,提示找不到该变量 Parent parent = new Parent();
parent.showByParent(); // Child child = new Child();
child.showByChild();
child.showByParent(); // 2(同样也是就近原则,访问的是父类中的成员变量i的值,虽然是子类对象的调用)
child.showByChildEx(6);
}
} // 子类
class Child extends Parent {
// 成员变量
public int i = 4;
public int j = 3; // 成员方法
public void method() {
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
System.out.println("增加一些距离");
} public void showByChild() {
System.out.println("Child类中访问i:" + i); //
System.out.println("Child类中访问j:" + j); // 3
// 语法出错:k cannot be resolved to a variable
// System.out.println("Child类中访问k:" + k);
} public void showByChildEx(int i) {
System.out.println("Child类中访问局部变量i:" + i); //
System.out.println("Child类中访问成员变量i:" + this.i); //
}
} //父类
class Parent {
// 成员变量
public int i = 2; // 成员方法
public void showByParent() {
System.out.println("Parent类中访问i:" + i); //
}
}
 package cn.temptation;

 public class Sample05 {
public static void main(String[] args) {
// 使用子类的成员方法分别访问 局部变量、子类的成员变量、父类的成员变量
// 1、局部变量:直接访问
// 2、子类的成员变量:使用this.成员变量进行访问
// 3、父类的成员变量:Java中提供了 super 关键字,使用super.成员变量进行访问 Baby baby = new Baby();
baby.showByBaby(); // 注意:super关键字是无法访问父类的成员方法中的局部变量的,也是无法访问父类的私有成员变量
}
} // 父类
class Father {
// 成员变量
public int i = 2;
private int x = 5; // 成员方法
public void showByFather() {
System.out.println("父类的show方法");
// 局部变量
int y = 6;
System.out.println("父类的成员方法中的局部变量y:" + y);
}
} // 子类
class Baby extends Father {
// 成员变量
public int i = 3; // 成员方法
public void showByBaby() {
// 局部变量
int i = 4; System.out.println("子类的show方法"); System.out.println("子类的局部变量i:" + i);
System.out.println("子类的成员变量i:" + this.i);
System.out.println("父类的成员变量i:" + super.i);
// 语法错误:The field Father.x is not visible
// System.out.println("父类的私有成员变量x:" + super.x); super.showByFather();
}
}
 package cn.temptation;

 public class Sample06 {
public static void main(String[] args) {
// 继承关系的父类子类创建对象时的执行顺序(结合断点观察,子类创建对象使用无参构造函数)
// 1、实例化子类,因为new的是子类,所以先走到子类的无参构造函数
// 2、并没有走入子类的无参构造函数中,而是依据extends继承关系,找到其父类的无参构造函数
// 3、走入父类的无参构造函数中,执行父类的无参构造函数要做的相关操作
// 4、接着再走入子类的无参构造函数中,执行子类的无参构造函数要做的相关操作
Son son = new Son();
System.out.println(son); // 继承关系的父类子类创建对象时的执行顺序(结合断点观察,子类创建对象使用有参构造函数)
// 1、实例化子类,因为new的是子类,所以先走到子类的有参构造函数
// 2、并没有走入子类的有参构造函数中,而是依据extends继承关系,找到其父类的无参构造函数
// 3、走入父类的无参构造函数中,执行父类的无参构造函数要做的相关操作
// 4、接着再走入子类的有参构造函数中,执行子类的有参构造函数要做的相关操作
// Son son = new Son(6);
// System.out.println(son); // 注意:
// 1、子类对象的创建,会依据继承关系找到父类的无参构造函数,走入其中,那么也就在堆中开辟了相应的空间存储父类对象(想一想,super关键字可以访问父类的非私有成员)
// 2、子类对象的创建,会依据继承关系找到父类的无参构造函数,为什么找的是父类的无参构造函数而不是有参构造函数?
// 答:因为不写构造函数,JDK会自动生成无参构造函数,显然子类在依据继承关系时,找父类的无参构造函数即可(不论是自己写的还是JDK生成),找有参构造函数可能找不到
// 3、所谓的new,就是去调用合适(匹配参数列表)的构造函数,构造有构建创造的意思,new的执行会调用并走入构造函数中
// 换句话说,执行了构造函数,就在堆内存中开辟了空间 // this.子类自身的成员(this指的是当前对象)
// super.父类的成员(super指的是当前对象的父类对象) // super() :当前对象的父类的无参构造函数
// super(param) :当前对象的父类的有参构造函数 // 1、子类的构造函数中不显式的指明对父类构造函数的调用,默认会执行对父类无参构造函数的调用
// 2、子类的构造函数中显式的指明对父类无参构造函数的调用,会执行对父类无参构造函数的调用
// 3、子类的构造函数中显式的指明对父类有参构造函数的调用,会执行对父类有参构造函数的调用,不会执行对父类无参构造函数的调用
}
} // 父类
class Dad {
// 成员变量 // 构造函数
public Dad() {
System.out.println("父类的无参构造函数");
} public Dad(int param) {
System.out.println("父类的有参构造函数");
}
} // 子类
class Son extends Dad {
// 成员变量 // 构造函数
public Son() {
// 调用父类的无参构造函数
// super();
// 调用父类的有参构造函数
// super(100);
System.out.println("子类的无参构造函数"); // 注意:子类的构造函数中的父类构造函数调用必须位于子类构造函数中的第一行,写在其他语句之后会产生语法错误
// 语法错误:Constructor call must be the first statement in a constructor
// super();
} public Son(int param) {
System.out.println("子类的有参构造函数");
}
}
 package cn.temptation;

 public class Sample07 {
public static void main(String[] args) {
// 在父类中手写了有参构造函数,但是没有手写无参的构造函数,子类中不论是无参构造函数还是有参构造函数均提示语法错误
// 语法错误:Implicit super constructor FatherEx() is undefined. Must explicitly invoke another constructor
// 原因:在类中,不手写无参构造函数,JDK为类自动创建无参构造函数;一旦手写了有参构造函数,JDK不会为类自动创建无参构造函数
// 而子类从父类继承,创建子类对象时会去找父类的无参构造函数,自然找不到了,所以语法出错
// 解决方案:使用构造函数时,都补上无参构造函数,这样可以避免语法出错
}
} // 父类
class FatherEx {
// 构造函数(有参)
public FatherEx(int param) {
System.out.println("这是父类的有参构造函数");
}
} // 子类
//class SonEx extends FatherEx {
// // 构造函数(无参)
// // 语法错误:Implicit super constructor FatherEx() is undefined. Must explicitly invoke another constructor
//// public SonEx() {
//// System.out.println("这是子类的无参构造函数");
//// }
//
// // 语法错误:Implicit super constructor FatherEx() is undefined. Must explicitly invoke another constructor
//// public SonEx(int param) {
//// System.out.println("这是子类的无参构造函数");
//// }
//}
 package cn.temptation;

 public class Sample08 {
public static void main(String[] args) {
// 类中常用的三个部分:成员变量、构造函数、成员方法 // 有继承关系的子类的实例化时,会涉及到几块内容?
// 答:涉及到父类 和 子类的成员变量、构造函数,但是和成员方法无关 // 有继承关系的子类的实例化的顺序(结合断点)
// 1、实例化子类,因为new的是子类,所以先走到子类的构造函数
// 2、并没有走入子类的构造函数中,而是依据extends继承关系,找到其父类的构造函数
// 3、并没有走入父类的构造函数中,而是对父类中的成员变量执行初始化操作
// 4、走入父类的构造函数中,执行父类构造函数要做的相关操作
// 5、接着对子类中的成员变量执行初始化操作
// 4、走入子类的构造函数中,执行子类构造函数要做的相关操作 SonDemo son = new SonDemo();
System.out.println(son);
son.showBySon();
}
} // 父类
class FatherDemo {
// 成员变量
private int age = 40;
public String name = "父亲"; // 构造函数
public FatherDemo() {
// super();
System.out.println("父类的构造函数");
} // 成员方法
public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} // 自定义的成员方法
public void showByFather() {
System.out.println("父类的show方法");
}
} // 子类
class SonDemo extends FatherDemo {
// 成员变量
private int weight = 5;
public String info = "孩子"; // 构造函数
public SonDemo() {
// super();
System.out.println("子类的构造函数");
} // 成员方法
public int getWeight() {
return weight;
} public void setWeight(int weight) {
this.weight = weight;
} public String getInfo() {
return info;
} public void setInfo(String info) {
this.info = info;
} // 自定义的成员方法
public void showBySon() {
System.out.println("子类的show方法");
}
}
 package cn.temptation;

 public class Sample09 {
public static void main(String[] args) {
// 有继承关系的子类 和 父类结构中有静态代码块、构造代码块、构造函数、成员变量等,子类的实例化执行顺序是什么样的? // 1、首先走到子类的实例化语句
// 2、走到父类的静态成员变量,进行初始化
// 3、走到父类的静态代码块
// 4、走到子类的静态成员变量,进行初始化
// 5、走到子类的静态代码块
// 6、走到子类的构造函数,但是不走入其中
// 7、走到父类的构造函数,但是不走入其中
// 8、走到父类的非静态成员变量,进行初始化
// 9、走到父类的构造代码块
// 10、走到父类的构造函数中
// 11、走到子类的非静态成员变量,进行初始化
// 12、走到子类的构造代码块
// 13、走到子类的构造函数中 ChildEx child1 = new ChildEx();
System.out.println(child1); ChildEx child2 = new ChildEx();
System.out.println(child2);
}
} // 父类
class ParentEx {
// 成员变量
private int age = 40;
public String name = "父亲";
// 静态成员变量
public static String gender = "男"; // 静态代码块
static {
System.out.println("父类的静态代码块");
} // 构造代码块
{
System.out.println("父类的构造代码块");
} // 构造函数
public ParentEx() {
// super();
System.out.println("父类的构造函数");
}
} // 子类
class ChildEx extends ParentEx {
// 成员变量
private int weight = 5;
public String info = "孩子";
// 静态成员变量
public static String country = "中国"; // 静态代码块
static {
System.out.println("子类的静态代码块");
} // 构造代码块
{
System.out.println("子类的构造代码块");
} // 构造函数
public ChildEx() {
// super();
System.out.println("子类的构造函数");
}
}
 package cn.temptation;

 public class Sample10 {
public static void main(String[] args) {
// 继承关系中父类子类的成员方法的使用
// 1、子类的成员方法 和 父类的成员方法不同名时,子类对象随便调用,都可以访问
// 2、子类的成员方法 和 父类的成员方法同名时,使用的是子类的成员方法
// 此时,好像父类虽然把其成员(非私有的)都给了子类,但是子类把从父类继承过来的同名的成员进行了覆盖一样 // Java中这种现象称为 重写(覆盖)Override // ChildSample child = new ChildSample();
// child.showByParent(); // 父类的showByParent方法
// child.showByChild(); // 子类的showByChild方法
// child.show(); // 子类的show方法 /*
* 对比:说明Override 和 Overload 的区别?
* Override:重写(覆盖),子类的成员 和 父类的成员同名时,子类对象使用时使用子类成员的现象
* Overload:重载,描述的是方法使用时,相同的方法名,不同的参数列表的现象
*/
}
} //// 父类
//class ParentSample {
// // 成员方法
// public void showByParent() {
// System.out.println("父类的showByParent方法");
// }
//
// public void show() {
// System.out.println("父类的show方法");
// }
//}
//
//// 子类
//class ChildSample extends ParentSample {
// // 成员方法
// public void showByChild() {
// System.out.println("子类的showByChild方法");
// }
//
// public void show() {
// System.out.println("子类的show方法");
// }
//}
 package cn.temptation;

 public class Sample11 {
public static void main(String[] args) {
// 重写的特点:
// 1、重写时,子类的方法和父类的方法不但方法名相同,而且参数列表相同(参数类型相同,参数名可以不同)
// 2、重写时,子类的方法和父类的方法不但方法名相同,而且参数列表相同,而且返回值类型也要相同
// 3、重写时,子类既可以继续使用父类的成员方法,又可以不使用父类的成员方法
// 这里有两层含义:
// A:完全覆盖:完全不用父类的成员方法的内容,重新来一套
// B:部分覆盖:父类的成员方法的内容还继续用,加一些新的内容形成自己的成员方法
// 只需要在子类的成员方法中使用super.父类的成员方法就可以继续使用父类的成员方法的内容
ChildSample child = new ChildSample();
child.method(123);
child.use();
}
} // 父类
class ParentSample {
// 成员方法
public void showByParent() {
System.out.println("父类的showByParent方法");
} public void show() {
System.out.println("父类的show方法");
} public void method(int i) {
System.out.println("父类的有参method方法");
} public void use() {
System.out.println("父类的use方法");
}
} // 子类
class ChildSample extends ParentSample {
// 成员方法
public void showByChild() {
System.out.println("子类的showByChild方法");
} public void show() {
System.out.println("子类的show方法");
} // 如下这个method方法就覆盖了父类中继承过来的method方法
// public void method(int x) {
// System.out.println("子类的有参method方法");
// } // 如下这个method方法,如果父类中没有method方法,这样写是没有语法错误的
// 但是父类中有method方法,如下的写法因为返回值类型和父类中的不一致,产生语法错误
// 语法错误:The return type is incompatible with ParentSample.method(int)
// public String method(int i) {
// System.out.println("子类的有参method方法");
// return "返回值";
// } public void use() {
super.use();
System.out.println("子类的use方法");
}
}
 package cn.temptation;

 public class Sample12 {
public static void main(String[] args) {
// 关于重写的一些问题:
// 1、父类的私有成员方法 和 子类的公有成员方法,同名、参数列表相同,这是不是重写? 答:这种不是重写
// 原因:因为子类都访问不到父类的私有成员方法,还谈什么覆盖呢?
// 2、父类的公有成员方法 和 子类的私有成员方法,同名、参数列表相同,语法错误:Cannot reduce the visibility of the inherited method from ParentTest
// 不能修改子类中继承自父类(重写父类)方法的访问修饰符权限
// 3、重写时,子类的方法 和 父类的方法建议写的完全一致(指的是形式的完全一致,方法的内容可以不一致)
// IDE提供了重写的便捷操作:在子类中书写和父类中相同的成员方法名,会自动生成相同的方法结构
ChildTest child = new ChildTest();
child.show();
}
} // 父类
class ParentTest {
private void show(){
System.out.println("父类的私有show方法");
} public void use() {
System.out.println("父类的公有use方法");
} public void test(String param) {
System.out.println("父类的公有有参test方法");
}
} // 子类
class ChildTest extends ParentTest {
public void show(){
System.out.println("子类的公有show方法");
} // 语法错误:Cannot reduce the visibility of the inherited method from ParentTest
// private void use() {
// System.out.println("子类的私有use方法");
// } @Override
public void test(String param) {
super.test(param);
}
}
 package cn.temptation;

 public class Sample13 {
public static void main(String[] args) {
// 需求:使用继承、重写等技术点实现如下功能:
// Tom猫是一种动物,3岁,吃鱼喝着牛奶,晒太阳
// Snoppy狗是一种动物,2岁,吃肉喝着可乐,看大门 Cat cat = new Cat("Tom", 3);
cat.eat("鱼");
cat.bask("太阳"); Dog dog = new Dog("Snoppy", 2);
dog.eat("肉");
dog.guard("大门");
}
} // 动物类(父类)
class Animal {
// 成员变量
// 姓名
private String name;
// 年龄
private int age; // 构造函数
public Animal() {
super();
} public Animal(String name, int age) {
super();
this.name = name;
this.age = age;
} // 成员方法
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} // 自定义成员方法
public void eat(String food) {
// 一般的动物,就知道吃,吃的时候不知道喝
System.out.print("吃" + food);
}
} // 猫类
class Cat extends Animal {
// 构造函数
public Cat() {
super();
} public Cat(String name, int age) {
// 写法1、使用局部变量
// System.out.println("名字为:" + name + ",年龄为:" + age); // 写法2、使用父类对象的成员变量
// super.setName(name);
// super.setAge(age);
// System.out.println("名字为:" + super.getName() + ",年龄为:" + super.getAge()); // 写法3、使用子类对象的成员变量(这里的成员变量继承自父类对象)
this.setName(name);
this.setAge(age);
System.out.println("名字为:" + this.getName() + ",年龄为:" + this.getAge());
} // 成员方法
/**
* 重写父类的eat方法
*/
@Override
public void eat(String food) {
super.eat(food);
System.out.println("喝牛奶");
} public void bask(String obj) {
System.out.println("晒" + obj);
}
} // 狗类
class Dog extends Animal {
// 构造函数
public Dog() {
super();
} public Dog(String name, int age) {
System.out.println("名字为:" + name + ",年龄为:" + age);
} // 成员方法
/**
* 重写父类的eat方法
*/
@Override
public void eat(String food) {
super.eat(food);
System.out.println("喝可乐");
} public void guard(String obj) {
System.out.println("看" + obj);
}
}
上一篇:《第一行代码--Android》阅读笔记之界面设计


下一篇:类库探源——System.Delegate