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 - 面向对象的更多相关文章

  1. Java学习笔记之---面向对象

    Java学习笔记之---面向对象 (一)封装 (1)封装的优点 良好的封装能够减少耦合. 类内部的结构可以自由修改. 可以对成员变量进行更精确的控制. 隐藏信息,实现细节. (2)实现封装的步骤 1. ...

  2. Java学习笔记之面向对象、static关键字

    一周Java学习总结 今天就总结理清一下关于面向对象和面向过程的程序设计的一些不同特点,以及讲下static关键字. 面向对象 现在接触的Java是面向对象的,现在的程序开发几乎都是以面向对象为基础的 ...

  3. Java 学习笔记(4)——面向对象

    现在一般的语言都支持面向对象,而java更是将其做到很过分的地步,java是强制使用面向对象的写法,简单的写一个Hello Word都必须使用面向对象,这也是当初我很反感它的一点,当然现在也是很不喜欢 ...

  4. 【原】Java学习笔记019 - 面向对象

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 仔细想一想,Ani ...

  5. 【原】Java学习笔记016 - 面向对象

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // this 关键字 ...

  6. 【原】Java学习笔记014 - 面向对象

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 面向对象思想 // ...

  7. 【原】Java学习笔记020 - 面向对象

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 成员方法的参数列表 ...

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

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 继承关系中的pri ...

  9. 【原】Java学习笔记015 - 面向对象

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 传递 值类型参数 ...

随机推荐

  1. MT2018笔试题之计算数字位数

    一.计算数字位数 1.题目 给定一个数字T,计算从1到T的所有正整数的位数和.比如T=13,则12345678910111213有17位数字. 输入描述 3 13 4 5 输出 17 4 5 2.思路 ...

  2. 版本管理工具Git(三)Gitlab高可用

    高可用模式 企业版 社区版 我们这里说一下成本比较低的主备模式,它主要依赖的是DRBD方式进行数据同步,需要2台ALL IN ONE的GitLab服务器,也就是通过上面安装方式把所有组件都安装在一起的 ...

  3. 适用于app.config与web.config的ConfigUtil读写工具类

    之前文章:<两种读写配置文件的方案(app.config与web.config通用)>,现在重新整理一个更完善的版本,增加批量读写以及指定配置文件路径,代码如下: using System ...

  4. [VsCode] 开发所使用的VsCode的插件

    vscode 的插件 必须 Chinese (Simplified) Language Pack for Visual Studio Code Markdown Preview Enhanced De ...

  5. C#工具:Bootstrap WPF Style,Bootstrap风格的WPF样式

    简介 GitHub地址:https://github.com/ptddqr/bootstrap-wpf-style 此样式基于bootstrap-3.3.0,样式文件里的源码行数都是指的这个版本.CS ...

  6. [ASP.NET] 如何利用Javascript分割檔案上傳至後端合併

    最近研究了一下如何利用javascript進行檔案分割上傳並且透過後端.特地記錄一下相關的用法 先寫限制跟本篇的一些陷阱 1.就是瀏覽器的支援了 因為本篇有用到blob跟webworker 在ie中需 ...

  7. tar -P参数含义

    -p(小写) :保留备份数据的原本权限与属性,常用于备份(-c) 重要的配置文件-P(大写) :保留绝对路径,亦即允许备份数据中含有根目录存在之意: 在加上绝对路径出现的那个警告讯息“tar: Rem ...

  8. Ubuntu 18.04 安装java8

    step1: 添加ppa sudo add-apt-repository ppa:webupd8team/java sudo apt-get update step2: 安装oracle-java-i ...

  9. 【转】三个案例带你看懂LayoutInflater中inflate方法两个参数和三个参数的区别

    关于inflate参数问题,我想很多人多多少少都了解一点,网上也有很多关于这方面介绍的文章,但是枯燥的理论或者翻译让很多小伙伴看完之后还是一脸懵逼,so,我今天想通过三个案例来让小伙伴彻底的搞清楚这个 ...

  10. 看Android Stuido教程有感

    毕业两年了,之前一直都在另外的博客里写之前大学的经历,以及转载一些学习Android的点滴,原创的并不多.因为现在更多的是在博客园里逛,所以直到上个月还是鼓起勇气开通了博客,算来到今天也有一段时间了, ...