【原】Java学习笔记018 - 面向对象
package cn.temptation;
public class Sample01 {
public static void main(String[] args) {
// 继承关系的子类可以重写父类给它的成员方法
// 有时,父类不希望它的成员方法被子类重写(覆盖),对于这种要求,如何处理?
// 答:首先会想到把public 改为 private,但是这样会导致外部无法调用该方法。所以,Java提供了 final 关键字
// final 使用格式:
// 修饰符 final 成员方法(...) { ... }
}
}
//class Father {
//// public void show() {
//// System.out.println("这是父类的show方法");
//// }
//
// public final void show() {
// System.out.println("这是父类的show方法");
// }
//}
//
//class Baby extends Father {
// // 父类的show方法使用final修饰后,子类中就无法再重写show方法了
// // 语法错误:Cannot override the final method from Father
//// public void show() {
//// System.out.println("这是子类的show方法");
//// }
//}
package cn.temptation;
public class Sample02 {
public static void main(String[] args) {
// final关键字可以用来修饰 成员变量、成员方法 和 类
// final修饰类,该类不能被继承
// final修饰类的理解:断子绝孙
}
}
final class Test {
}
// Test类使用final修饰后,不能被继承
// 语法错误:The type TestEx cannot subclass the final class Test
//class TestEx extends Test {
//
//}
package cn.temptation;
public class Sample03 {
public static void main(String[] args) {
// final修饰成员变量:赋值一次后不能再进行赋值
// Child child = new Child();
// child.show();
// 常量:
// 1、字面量常量:true、false、123、'a'、"China"
// 2、自定义常量:使用final修饰符修饰的成员变量 final int i = 2;
// 所以,自定义常量一般也使用常量的编码规范:即全部字母均大写,如果是多个单词组成,使用下划线_连接
}
}
//class Parent {
// public int i = 2;
// public final int j = 4;
//
// // 对于非final修饰的成员变量,不进行初始化赋值,是可以使用其默认值
// public int x;
// // 对于final修饰的成员变量,必须进行初始化赋值
// // 语法错误:The blank final field y may not have been initialized
//// public final int y;
// // 先定义成员变量y,接着进行赋值也是有语法错误
//// y = 123;
//
// // 自定义常量一般也使用常量的编码规范:即全部字母均大写,如果是多个单词组成,使用下划线_连接
// public final int K = 100;
// public final boolean CHECK_FLAG = true;
//}
//
//class Child extends Parent {
// public void show() {
// // 下面两组代码效果相同
//// this.i = 3;
//// System.out.println(this.i);
//
// super.i = 3;
// System.out.println(super.i);
//
// // final修饰的成员变量不能被改变
// // 语法错误:The final field Parent.j cannot be assigned
//// this.j = 5;
//// System.out.println(this.j);
// // 语法错误:The final field Parent.j cannot be assigned
//// super.j = 5;
//// System.out.println(super.j);
// }
//}
package cn.temptation;
public class Sample04 {
public static void main(String[] args) {
// final修饰局部变量
// 1、final修饰值类型的局部变量,赋值一次后不能再赋值
// 2、final修饰引用数据类型的局部变量,new过一次后不能再new了,创建过一次引用数据类型对象后就不能再创建了
// 也就是说该局部变量在堆中有一个内存空间后就不能再创建新的内存空间了
int i = 2;
System.out.println(i);
i = 3;
System.out.println(i);
final int j = 4;
System.out.println(j);
// The final local variable j cannot be assigned. It must be blank and not using a compound assignment
// j = 5;
// System.out.println(j);
System.out.println("--------------------------------------");
// Demo demo = new Demo();
// System.out.println(demo);
// System.out.println(demo.k);
// demo = new Demo();
// demo.k = 88;
// System.out.println(demo);
// System.out.println(demo.k);
final Demo demoEx = new Demo();
System.out.println(demoEx);
System.out.println(demoEx.k);
// The final local variable demoEx cannot be assigned. It must be blank and not using a compound assignment
// demoEx = new Demo();
demoEx.k = 77;
System.out.println(demoEx);
System.out.println(demoEx.k);
// 注意:
// 使用final修饰的引用数据类型的局部变量虽然不能更改其在堆内存中创建的空间地址,但是其在堆内存中的成员变量的值还是可以修改的
}
}
class Demo {
int k = 99;
}
package cn.temptation;
public class Sample05 {
public static void main(String[] args) {
// 使用final、final static修饰的成员变量 与 构造代码块内外 赋值的问题
TestEx testEx = new TestEx();
}
}
class TestEx {
// 成员变量
int i = 2;
// 语法错误:The blank final field j may not have been initialized
final int j;
final int k = 3;
final static int m = 4;
// 语法错误:The blank final field n may not have been initialized
// final static int n;
final int x = 123;
final static int y = 987;
// 构造代码块
{
System.out.println(i);
i = 3;
System.out.println(i);
System.out.println(k);
// 语法错误:The blank final field j may not have been initialized
// System.out.println(j);
// 在构造代码块之前使用final修饰成员变量并不赋值,在构造代码块中进行赋值,语法OK
j = 5;
System.out.println(j);
// 在构造代码块之前使用final static修饰成员变量并不赋值,在构造代码块中进行赋值,语法也出错
// 语法错误:The final field TestEx.n cannot be assigned
// n = 6;
// System.out.println(n);
System.out.println(x);
// 对于构造代码块之前已经赋值的final修饰的成员变量,在构造代码块中进行赋值,语法也出错
// 语法出错:The final field TestEx.x cannot be assigned
// x = 456;
// System.out.println(x);
System.out.println(y);
// 对于构造代码块之前已经赋值的final static修饰的成员变量,在构造代码块中进行赋值,语法也出错
// 语法出错:The final field TestEx.y cannot be assigned
// y = 654;
// System.out.println(y);
}
}
package cn.temptation;
public class Sample06 {
public static void main(String[] args) {
// 多态的引入:
// 变形金刚:变化为不同的形态:一会儿是机器人,一会儿变成汽车
// 水:三种不同的形态:气态、液态、固态
// 多态:同一个对象,在不同的时间、场合表现出不同的形态或状态
// 比如:狗这个动物就是可爱啊!
// 这句话其实有几层意思:
// 1、狗是一种动物,也就是说狗从动物继承而来的,dog is an animal
// 2、描述的重点在动物上,这个动物在我们描述的时候以狗这种形态出现的
// 类似:猫这个动物就是要人哄啊!
// 多态的前提:
// 1、继承是多态的基础,必须有继承的关系,才可以探讨多态
// 2、要有override重写
// 3、要有父类的引用(声明)指向子类的对象:父类 对象名 = new 子类(); 父类在前,子类在后
// 对比:之前写法 子类 对象名 = new 子类();
// 理解:
// 狗 对象名 = new 狗(); 狗 是 狗 √
// 动物 对象名 = new 狗(); 狗 是 动物 √
// 狗 对象名 = new 动物(); 动物 是 狗 ×
// Son son = new Son();
// System.out.println(son);
// Father obj = new Son();
// System.out.println(obj);
// 语法错误:Type mismatch: cannot convert from Father to Son
// Son obj = new Father();
// System.out.println(obj);
// 多态中成员的关系:
// 1、成员变量
// 编译时去赋值号左侧的类型里找,执行时去赋值号左侧的类型里找
// 2、构造函数
// 是否是多态的写法不影响,都是通过继承关系先找到父类的构造函数,执行后再走入子类的构造函数
// 3、成员方法
// 编译时去赋值号左侧的类型里找,执行时去赋值号右侧的类型里找
// 4、静态成员变量
// 编译时去赋值号左侧的类型里找,执行时去赋值号左侧的类型里找
// 5、静态成员方法
// 编译时去赋值号左侧的类型里找,执行时去赋值号左侧的类型里找
// 非多态写法
// Son son = new Son();
// System.out.println(son); // cn.temptation.Son@15db9742
// System.out.println(son.i); // 3
// son.show(); // 子类的show方法
// System.out.println(son.m); // 5
// System.out.println(Son.m); // 5
// son.use(); // 子类的静态use方法
// Son.use(); // 子类的静态use方法
// 多态写法
Father obj = new Son();
System.out.println(obj); // cn.temptation.Son@15db9742
System.out.println(obj.i); //
obj.show(); // 子类的show方法
System.out.println(obj.m); //
System.out.println(Father.m); //
System.out.println(Son.m); //
obj.use(); // 父类的静态use方法
Father.use(); // 父类的静态use方法
Son.use(); // 子类的静态use方法
// 注意:
// 多态时,需要从 编译时 和 执行时 两个方面去观察
// 多态中,非静态的成员方法在执行时去赋值号右侧的类型中找相应的方法进行调用,这种调用也称为 后期调用
}
}
// 父类
class Father {
// 成员变量
public int i = 2;
public static int m = 4;
// 构造函数
public Father() {
System.out.println("父类的构造函数");
}
// 成员方法
public void show() {
System.out.println("父类的show方法");
}
public static void use() {
System.out.println("父类的静态use方法");
}
}
// 子类
class Son extends Father {
// 成员变量
public int i = 3;
public static int m = 5;
// 构造函数
public Son() {
System.out.println("子类的构造函数");
}
// 成员方法
public void show() {
System.out.println("子类的show方法");
}
public static void use() {
System.out.println("子类的静态use方法");
}
}
package cn.temptation;
public class Sample07 {
public static void main(String[] args) {
// 不用装刘备的时候,可以做自己,就可以用自己特有的play方法
// LiuShan personEx = new LiuShan();
// personEx.work();
// personEx.play();
// 让刘禅接替刘备的位置(多态的使用)
LiuBei person = new LiuShan();
System.out.println(person); // cn.temptation.LiuShan@15db9742
person.work();
// 让刘禅装刘备时,不能做自己,不能使用自己特有的play方法
// 语法错误:The method play() is undefined for the type LiuBei
// person.play();
// 问:非要使用子类中特有的成员方法,怎么办? 答:因为我们知道其对象其实是子类类型的对象,所以可以考虑使用一下强制类型装换
((LiuShan)person).play();
}
}
// 父类:刘备
class LiuBei {
public void work() {
System.out.println("千辛万苦打江山!");
}
}
// 子类:刘禅
class LiuShan extends LiuBei {
// 成员方法
// 重写父类的成员方法work
public void work() {
System.out.println("被逼着做主公,也不知道有多难受!");
}
// 子类特有的成员方法play
public void play() {
System.out.println("玩的都乐不思蜀了!");
}
}
package cn.temptation;
public class Sample08 {
public static void main(String[] args) {
// 多态的优点:
// 1、使用多态,让程序有较好的扩展性
// 2、使用多态,让程序由较好的健壮性(没有继承关系的两个类不能玩多态)
// 不使用多态的写法
// BasketBall basketBall = new BasketBall();
// basketBall.play();
//
// FootBall footBall = new FootBall();
// footBall.play();
//
// VolleyBall volleyBall = new VolleyBall();
// volleyBall.play();
// 使用多态的写法
// 写法1
// Sport basketBall = new BasketBall();
// basketBall.play();
//
// Sport footBall = new FootBall();
// footBall.play();
//
// Sport volleyBall = new VolleyBall();
// volleyBall.play();
// 写法2
// Sport sport1 = new BasketBall();
// sport1.play();
//
// Sport sport2 = new FootBall();
// sport2.play();
//
// Sport sport3 = new VolleyBall();
// sport3.play();
// 写法3(数组的动态初始化)
// 因为上面三个变量的类型都是一致的,所以考虑使用数组来存放一下,声明一个Sport类型的数组
// Sport[] sports = new Sport[3];
// sports[0] = new BasketBall();
// sports[1] = new FootBall();
// sports[2] = new VolleyBall();
// 写法4(数组的静态初始化)
Sport[] sports = {
new BasketBall(), // 匿名对象
new FootBall(),
new VolleyBall(),
new Swim()
};
for (Sport item : sports) {
item.play();
}
}
}
// 父类:运动类
class Sport {
public void play() {
System.out.println("做运动");
}
}
// 子类:篮球类
class BasketBall extends Sport {
@Override
public void play() {
System.out.println("篮球的玩法");
}
}
class FootBall extends Sport {
@Override
public void play() {
System.out.println("足球的玩法");
}
}
class VolleyBall extends Sport {
public void play() {
System.out.println("排球的玩法");
}
}
class Swim extends Sport {
@Override
public void play() {
System.out.println("游泳的玩法");
}
}
package cn.temptation;
public class Sample09 {
public static void main(String[] args) {
// 多态的缺点:
// 使用多态,对于子类有但是父类没有的成员方法(子类特有的成员方法),无法使用
// Parent obj = new Child();
// obj.show();
// 语法错误:The method use() is undefined for the type Parent
// obj.use();
// 要想使用子类特有的成员方法,只有在明确其实该对象是子类类型的对象时,进行强制类型转换
// ((Child)obj).use();
}
}
//class Parent {
// public void show() {
// System.out.println("父类的成员方法");
// }
//}
//
//class Child extends Parent {
// @Override
// public void show() {
// System.out.println("子类的成员方法");
// }
//
// public void use() {
// System.out.println("子类特有的成员方法");
// }
//}
package cn.temptation;
public class Sample10 {
public static void main(String[] args) {
// 对于多态的缺点:使用多态,对于子类有但是父类没有的成员方法(子类特有的成员方法),无法使用,非要使用,怎么办?
// 方法1、在父类中加上子类特有的成员方法,语法OK,但是不能这样写,因为这样就违背了父类设计的初衷
// 方法2、因为子类实际在替代父类的事情,所以在编译阶段只能用父类中的成员方法,
// 如果明确实际使用的是子类对象,使用时让其改为子类的类型,就可以使用其自己的成员方法了
// 把父类类型的变量名(引用)强制类型转换为子类类型的引用,称为多态的向下转型
// Parent obj = new Child();
// obj.show();
// 语法错误:The method use() is undefined for the type Parent
// obj.use();
// Parent obj = new Child();
// // 写法1
//// ((Child)obj).show();
//// ((Child)obj).use();
// // 写法2
// Child child = (Child) obj;
// child.show();
// child.use();
//
// // 不转型
// Child childEx = new Child();
// 所谓的转型:就是拿着赋值号右边的类型 和 赋值号左边的类型进行比较
// 右边的类型是左边类型的下级(子),向上转型
// 右边的类型是左边类型的上级(父),向下转型
Parent obj = new Child(); // 向上转型
Child child = (Child)obj; // 向下转型
// 没有关系的两个类,是无法进行强制类型转换的
// 语法错误:Cannot cast from Parent to Other
// Other other = (Other)obj;
}
}
class Parent {
public void show() {
System.out.println("父类的成员方法");
}
}
class Child extends Parent {
@Override
public void show() {
System.out.println("子类的成员方法");
}
public void use() {
System.out.println("子类特有的成员方法");
}
}
class Other {
public void show() {
System.out.println("其他类的成员方法");
}
}
package cn.temptation;
public class Sample11 {
public static void main(String[] args) {
// 多态的一些问题:
// 1、父类、子类都有的同名同参数列表成员方法,编译时找父类的成员方法,执行时找子类的成员方法
// 2、父类有、子类没有的成员方法,编译时找父类的成员方法,执行时找父类的成员方法(因为子类中没有重写该成员方法,所以使用父类中的成员方法)
ParentTest obj = new ChildTest();
obj.show();
}
}
class ParentTest {
public void show() {
System.out.println("父类有、子类没写的成员方法");
}
}
class ChildTest extends ParentTest {
}
package cn.temptation;
public class Sample12 {
public static void main(String[] args) {
Animal animal = new Dog();
animal.eat();
// animal.guard(); // 语法错误
Dog dog = (Dog) animal;
dog.guard();
// 执行出错,产生异常:java.lang.ClassCastException: cn.temptation.Dog cannot be cast to cn.temptation.Cat
// 原因:
// 第5行的animal变量是一个引用,animal变量的类型是Animal类类型,它指向堆内存中创建出的Dog类型的空间
// 下句的强制类型转换,是要把animal这个引用转换为Cat类型,如果正常的使用,那么这个cat变量的引用,应该指向堆内存中创建的Cat类型的空间
Cat cat = (Cat) animal; // 这句语法上没有错误,编译可以通过,是因为有继承关系的子类和父类可以进行向上转型 和 向下转型
cat.eat();
cat.bask();
// 本质上这样的写法就是"指鹿为马"
// 平行的两个子类,是无法进行强制类型转换的
Dog dogEx = new Dog();
Cat catEx = new Cat();
// 语法错误:Cannot cast from Dog to Cat
// catEx = (Cat)dogEx;
}
}
class Animal {
public void eat() {
System.out.println("动物都会吃");
}
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
public void guard() {
System.out.println("看门");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void bask() {
System.out.println("晒太阳");
}
}
【原】Java学习笔记018 - 面向对象的更多相关文章
- Java学习笔记之---面向对象
Java学习笔记之---面向对象 (一)封装 (1)封装的优点 良好的封装能够减少耦合. 类内部的结构可以自由修改. 可以对成员变量进行更精确的控制. 隐藏信息,实现细节. (2)实现封装的步骤 1. ...
- Java学习笔记之面向对象、static关键字
一周Java学习总结 今天就总结理清一下关于面向对象和面向过程的程序设计的一些不同特点,以及讲下static关键字. 面向对象 现在接触的Java是面向对象的,现在的程序开发几乎都是以面向对象为基础的 ...
- Java 学习笔记(4)——面向对象
现在一般的语言都支持面向对象,而java更是将其做到很过分的地步,java是强制使用面向对象的写法,简单的写一个Hello Word都必须使用面向对象,这也是当初我很反感它的一点,当然现在也是很不喜欢 ...
- 【原】Java学习笔记019 - 面向对象
package cn.temptation; public class Sample01 { public static void main(String[] args) { // 仔细想一想,Ani ...
- 【原】Java学习笔记016 - 面向对象
package cn.temptation; public class Sample01 { public static void main(String[] args) { // this 关键字 ...
- 【原】Java学习笔记014 - 面向对象
package cn.temptation; public class Sample01 { public static void main(String[] args) { // 面向对象思想 // ...
- 【原】Java学习笔记020 - 面向对象
package cn.temptation; public class Sample01 { public static void main(String[] args) { // 成员方法的参数列表 ...
- 【原】Java学习笔记017 - 面向对象
package cn.temptation; public class Sample01 { public static void main(String[] args) { // 继承关系中的pri ...
- 【原】Java学习笔记015 - 面向对象
package cn.temptation; public class Sample01 { public static void main(String[] args) { // 传递 值类型参数 ...
随机推荐
- Nginx 动静分离与负载均衡的实现
一.前提 企业中,随着用户的增长,数据量也几乎成几何增长,数据越来越大,随之也就出现了各种应用的瓶颈问题. 问题出现了,我们就得想办法解决,一般网站环境,均会使用LAMP或者LNMP,而我们对于网站环 ...
- Python - 命令式编程与符号编程
原文链接:https://zh.d2l.ai/chapter_computational-performance/hybridize.html本文是对原文内容的摘取和扩展. 命令式编程(imperat ...
- python-类的定制
1.看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的.__slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让cl ...
- flink metric库的使用和自定义metric-reporter
简单介绍 flink内部实现了一套metric数据收集库. 同时flink自身系统有一些固定的metric数据, 包括系统的一些指标,CPU,内存, IO 或者各个task运行的一些指标.具体包含那些 ...
- 受到 1 万点暴击,二狗子被 DDoS 攻击的惨痛经历
二狗子的遭遇 “好消息,好消息,免费 DDoS 攻击软件上线了,性感黑客在线攻击,帮您攻克所有商业难题.”二狗子不知道在看着什么网站,新买的 Mac 中发出热闹的声音. 二狗子想知道“DDoS 是什么 ...
- qt 窗口鼠标穿透
Qt 不规则窗体 – 鼠标点击穿透 qt实现鼠标穿透,如果要被穿透窗口只有一层,也即没有嵌套窗口,直接只用对子窗口使用setAttribute (Qt::WA_TransparentForMouseE ...
- es6学习笔记--模板字符串
这几天简单看了一下深入浅出es6这本书,感觉特实用,学习了一个新特性---模板字符串在项目开发中,拼接字符串是不可缺少的,动态创建dom元素以及js操作数据都要拼接字符串,在es6出来之前,我们都通常 ...
- SpringBoot入门教程(一)详解intellij idea搭建SpringBoot
最近公司有一个内部比赛(黑客马拉松),报名参加了这么一个赛事,在准备参赛作品的同时,由于参赛服务器需要自己搭建且比赛产生的代码不能外泄的,所以借着这个机会,本地先写了个测试的demo,来把tomcat ...
- 使用mpvue开发小程序教程(六)
在上一章节中,我们列举了在Vue中能用但在mpvue中不能用或需要特别注意的特性,在实际开发前了解一下还是很有必要的,可以避免浪费找错误的时间. 如果你使用过原生的小程序框架,你一定经历过或思考过怎么 ...
- 初学Java Web(5)——cookie-session学习
HTTP 协议 Web 浏览器与 Web 服务器之间的一问一答的交互过程必须遵守一定的规则,这样的规则就是 HTTP 协议. HTTP 是 hypertext transfer protocol(超文 ...