1.回顾-泛化
泛化:父类的引用指向子类的对象
泛化的好处:统一管理,实现多态
泛化的缺点:丢失具体信息
再一次确认往下转型是不安全的
如何安全:先判断类型xx instanceof 类
1.1、instanceof
使用instanceof时,对象的类型必须和instanceof后面的参数所指定的类在继承上有上下级关系
使用:xx instanceof 类
1.抽象(abstract)
假的 只有名字没有具体实现
- 如果一个类中有抽象方法,那么它的类一定是抽象类。
- 抽象类中不一定有抽象方法。
- 抽象类是不能实例化的,不能new,但抽象类是有构造方法的,并且可以重载
- 抽象类中可以有具体方法和成员变量
- 抽象类在被子类继承时,必须实现抽象类的所有抽象方法,否则子类也是抽象类。
代码案例:计算体积
public class JuXing extends Ban{
private double a;
private double b;
//private double h;
public JuXing(double a, double b, double h) {
super(h);
this.a = a;
this.b = b;
//this.h = h;
}
@Override
public double mianJi() {
return a*b;
}
/*@Override
public double tiJi(){
double mianJi = a*b;
return mianJi*getH();
}*/
}
public class SanJiao extends Ban{
private double a;
private double b;
private double c;
//private double h;
public SanJiao(double a, double b, double c, double h) {
super(h);
this.a = a;
this.b = b;
this.c = c;
//this.h = h;
}
@Override
public double mianJi() {
double p = (a+b+c)/2;
return Math.sqrt(p*(p-a)*(p-b)*(p-c));
}
/*@Override
public double tiJi(){
double p = (a+b+c)/2;
double mianJi = Math.sqrt(p*(p-a)*(p-b)*(p-c));
return mianJi*getH();
}*/
}
public class Yuan extends Ban{
private double c;
//private double h;
public Yuan(double c, double h) {
super(h);
this.c = c;
//this.h = h;
}
@Override
public double mianJi() {
double r = (c/Math.PI)/2;
return r*r*Math.PI; //Math.pow(r,2)*Math.PI;
}
/*@Override
public double tiJi(){
double r = (c/Math.PI)/2;
double s = r*r*Math.PI; //Math.pow(r,2)*Math.PI;
return s*getH();
}*/
}
public abstract class Ban {
public abstract double mianJi();
public double tiJi(){
return mianJi()*h; // 多态
}
private double h;
public double getH() {
return h;
}
public void setH(double h) {
this.h = h;
}
public Ban() {
}
public Ban(double h) {
this.h = h;
}
}
public class Test {
public static void main(String[] args) {
//Object[] bans = new Object[3];
Ban[] bans = new Ban[3];
bans[0] = new JuXing(1.3,0.7,0.5);
bans[1] = new Yuan(3.6,0.7);
bans[2] = new SanJiao(1.2,1.1,0.7,0.4);
double tiJiHe = 0.0;
// 怎么计算体积和
for (Ban obj: bans) {
tiJiHe+=obj.tiJi();
/*if (obj instanceof JuXing){ // 判断一个变量是不是某种类型
System.out.println("juxing.......");
tiJiHe += ((JuXing)obj).tiJi(); // 强转:往下转型
}
if (obj instanceof Yuan){ // 判断一个变量是不是某种类型
System.out.println("yuan........");
tiJiHe += ((Yuan)obj).tiJi(); // 强转:往下转型
}
if (obj instanceof SanJiao){ // 判断一个变量是不是某种类型
System.out.println("sanjiao........");
tiJiHe += ((SanJiao)obj).tiJi(); // 强转:往下转型
}*/
}
System.out.println(tiJiHe);
}
}
2.接口(interface)
使用interface
修饰的类就是接口,接口的本质也是类,比抽象类还抽象的类
接口比抽象类 假的更彻底
子类继承接口时,子类必须实现接口中的所有方法,否则子类也只能是抽象接口,
接口不能实例化,
接口中没有构造方法
接口的意义
- 规定协议
- 模拟多继承 接口是:is-like
接口种所有方法默认是public abstract
当子类实现一个接口时,子类实现接口的所有方法
1.案例1
使用了接口隔离原则
public interface EatAble {
void eat();
}
public interface SayAble {
void say();
}
public abstract class Pet {
//public abstract void eat();
private Date bron;
private String type;
public Pet() {
}
public Pet(Date bron, String type) {
this.bron = bron;
this.type = type;
}
public Date getBron() {
return bron;
}
public void setBron(Date bron) {
this.bron = bron;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
public class Dog extends Pet implements EatAble,SayAble{
private String name;
@Override
public void eat() {
System.out.println(name+"在坑骨头!");
}
@Override
public void say() {
System.out.println(getType()+"叫妈妈了");
}
public Dog() {
}
public Dog(Date bron, String type, String name) {
super(bron, type);
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Pig extends Pet implements EatAble{
private double weight;
@Override
public void eat() {
System.out.println(super.getType()+"的猪的体重为:"+weight);
}
public Pig() {
}
public Pig(Date bron, String type, double weight) {
super(bron, type);
this.weight = weight;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
public abstract class Person {
//public abstract void eat();
private Date bron;
private String name;
public Person() {
}
public Person(Date bron, String name) {
this.bron = bron;
this.name = name;
}
public Date getBron() {
return bron;
}
public void setBron(Date bron) {
this.bron = bron;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Student extends Person implements EatAble,SayAble{
public String gender;
@Override
public void eat() {
System.out.println(getName()+"同学在吃牛排,性别是:"+gender);
}
@Override
public void say() {
System.out.println(getName()+"同学是:"+gender+" 生");
}
public Student() {
}
public Student(Date bron, String name, String gender) {
super(bron, name);
this.gender = gender;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
public class Teacher extends Person implements EatAble,SayAble{
private String zhuanye;
@Override
public void eat() {
System.out.println(getName()+"老师在吃龙虾,教的专业是:"+zhuanye);
}
@Override
public void say() {
System.out.println(getName()+"正在讲:"+zhuanye);
}
public Teacher() {
}
public Teacher(Date bron, String name, String zhuanye) {
super(bron, name);
this.zhuanye = zhuanye;
}
public String getZhuanye() {
return zhuanye;
}
public void setZhuanye(String zhuanye) {
this.zhuanye = zhuanye;
}
}
public class Test {
public static void main(String[] args) {
Object[] objects = new Object[4];
objects[0] = new Teacher(new Date(),"张老师","大数据");
objects[1] = new Student(new Date(),"韩美","女");
objects[2] = new Dog(new Date(),"哈士奇","贝贝");
objects[3] = new Pig(new Date(),"荷兰猪",334.3);
for (int i = 0; i < objects.length; i++) {
if (objects[i] instanceof EatAble){
EatAble obj = (EatAble) objects[i]; // 往下转型,不安全
obj.eat(); // 多态
}
/*if (objects[i] instanceof Pet){
Pet obj = (Pet) objects[i]; // 往下转型,不安全
obj.eat();
}*/
if (objects[i] instanceof SayAble){
SayAble obj = (SayAble) objects[i];
obj.say(); // 多态
}
}
}
}
2.案例2:打印墨盒
使用了里氏替换原则
// 当子类实现一个接口时,子类实现接口的所有方法
public class A4 implements Pager{
@Override
public String getTypeInfo() {
return "A4纸张";
}
}
public class B5 implements Pager{
@Override
public String getTypeInfo() {
return "B5纸张";
}
}
public interface Pager {
String getTypeInfo();
}
public class BlackWhiteInkBox implements InkBox{
@Override
public String getTypeInfo() {
return "黑白墨盒";
}
}
public class MutiColorInkBox implements InkBox{
@Override
public String getTypeInfo() {
return "彩色墨盒";
}
}
public interface InkBox {
String getTypeInfo();
}
public class Printer {
// 打印机在定义成员时,使用的是接口,而不是具体类型。
// 这种编程思考的现象称为:面向接口编程
// 接口类型:InkBox
private InkBox inkBox;
private Pager pager;
public void setInkBox(InkBox inkBox) {
this.inkBox = inkBox;
}
public void setPager(Pager pager) {
this.pager = pager;
}
public void print(String helloWorld) {
System.out.println("使用"+inkBox.getTypeInfo()+"在"+pager.getTypeInfo()+"打印:"+helloWorld);
}
}
public class Test {
public static void main(String[] args) {
// 创建一台打印机
Printer p = new Printer();
// 为打印机安装黑白墨盒
p.setInkBox(new BlackWhiteInkBox());
// 装上A4纸张
p.setPager(new A4());
// 开始打印
p.print("helloWorld2222222222");
System.out.println("要换纸张吗?");
// 换纸张为B5,不用换打印机
p.setPager(new B5());
// 希望在新类型的纸张上打印B5
p.print("helloWorld11111111111");
// 换墨盒为 彩色
System.out.println("换墨");
p.setInkBox(new MutiColorInkBox());
p.print("helloWorld3333333333333333");
}
}
3.案例3:手机功能案例
使用接口隔离原则
public interface CallPhoneable {
public void callPhone(String phoneNum);
}
public interface Sendable {
public void sendMsg(String msg);
}
public class OldPhone extends Phone implements CallPhoneable,Sendable{
public OldPhone(String s) {
super(s);
}
@Override
public void callPhone(String phoneNum) {
System.out.println(getNo()+"正在呼叫"+phoneNum);
}
@Override
public void sendMsg(String msg) {
System.out.println(getNo()+"正在发短信,内容是:"+ msg);
}
}
public class BBPhone extends Phone implements Sendable{
public BBPhone(String no) {
super(no);
}
@Override
public void sendMsg(String msg) {
System.out.println(msg+"正在发短信");
}
}
public class Phone /*implements Sendable,CallPhoneable*/{
public String no;
public Phone(String no) {
this.no = no;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
/*public void run() {
// 发短信
sendMsg("我爱你");
callPhone("c123456789");
}
@Override
public void sendMsg(String msg) {
System.out.println("发送消息"+msg);
}
@Override
public void callPhone(String phoneNum) {
System.out.println("拨打"+phoneNum+"电话");
}*/
}
public class Test {
public static void main(String[] args) {
/*Phone p = new Phone();
// 发短信
p.run();*/
Phone p = new OldPhone("010334324");
// 要理解 为什么正确 因为OldPhone具有打电话的能力,也就是相当于继承了
//CallPhoneable c = new OldPhone("234"); // 泛化
// 为什么不对 因为BBPhone不具备打电话的功能, 也就是相当于没继承
//CallPhoneable cc = new BBPhone("3");
if (p instanceof CallPhoneable){
((CallPhoneable) p).callPhone("0101111111111");
}else {
System.out.println("不具备打电话的功能!");
}
if (p instanceof Sendable){
((Sendable) p).sendMsg("我爱你");
}else {
System.out.println("不具备发短信的功能");
}
}
}
3.面向对象的设计原则(8种)
接口隔离原则
里氏替换原则
4.接口继承接口
主要用在接口组合这种场景下
interface 接口名 extends 接口1,接口2...{
}
代码案例:
public class Test {
public static void main(String[] args) {
}
}
interface A{
void foo();
}
interface B{
void show();
}
// 组合A和B 组合接口:叫接口继承
// 类不能继承接口,接口可以继承多个接口
interface F extends A,B{
}
class C implements F{
@Override
public void foo() {
}
@Override
public void show() {
}
}
5.static(静态)
final 可以修饰类,方法,变量(常量)
static 修饰类,方法,成员变量(共享量),
代码案例:
public class Test {
/**
* static 学习
* java 时面向对象的设计语言,但是保留了非面向对象的内容
*
* static 与对象无关
*
* static main方法,这是一个与对象没有关系的方法,称呼为静态方法
* 调用时,不依赖对象,只依赖类
* 由于static与对象无关,所以static方法中永远不能出现this
*
* foo方法 与对象息息相关的方法,称呼为成员方法或者对象方法
* 调用时,必须依赖对象
* 所以所有的对象方法都隐含了一个变量 这个变量名是:this
* 在本质上Java对象方法都应该是有参数的
*
* @param args
*/
int i = 19; // 成员变量,成员即对象
public static void main(String[] args) {
System.out.println(args.length);
System.out.println(args[0]);
//System.out.println(args[1]);
//foo();
new Test().foo();
}
public void foo(Test this){
System.out.println("hello static");
}
public void show(){
System.out.println("dfsfs");
foo();
}
public Test myself(){
return this;
}
}
静态变量
public class Test2 {
int i;
static int n;
public static void main(String[] args) {
Test2 t = new Test2();
Test2 t2 = new Test2();
t.i++;
System.out.println(t.i); //1
System.out.println(t2.i); //0
System.out.println("---------");
Test2.n++;
System.out.println(Test2.n); //1
System.out.println(Test2.n); //1
}
}
6.变量有几类?
成员变量
局部变量
7.内部类
内部类有3种:静态内部类,成员内部类,匿名内部类
内部类分三种:
- 静态内部类,:使用时和静态变量,静态方法一样,依赖外部类使用
- 成员内部类,:使用时和成员变量,成员方法一样,必须依赖对象
- 匿名内部类 : 没有名字的类,只能使用一次
有两个this:一个外部类this,一个内部类this
外部类的this是外部类名.this
内部类可以访问外部类的private修饰的东西,
外部类也可以访问内部类private修饰的东西
代码案例
public class Test {
/**
* 内部类学习
* 顾名思义:在类的内部定义类
*
* 内部类分三种:
* 静态内部类,:使用时和静态变量,静态方法一样,依赖外部类使用
* 成员内部类,:使用时和成员变量,成员方法一样,必须依赖对象
* 匿名内部类 : 没有名字的类,只能使用一次
*
* @param args
*/
public static void main(String[] args) {
// 成员内部类的创建必须依赖外部类对象
new Test().new A();
// 静态内部类 :这个地方new的是B,而不是Test
new Test.B();
// 定义匿名内部类,并调用say方法
Person p = new Person(){
@Override
public void say() {
System.out.println("匿名内部类。。。。。");
}
}; // 泛化
p.say(); // 多态
// 匿名内部类
Eatable e = new Eatable() {
@Override
public void eat() {
System.out.println("学会编程");
}
};
e.eat();
// lambda表达式 函数 lambda表达式只能拥有一个接口中只有一个对象
Eatable e2 = () -> System.out.println("牛不牛");
e2.eat();
}
// 成员内部类
class A{
}
// 静态内部类
static class B{
}
}
abstract class Person{
public abstract void say();
}
interface Eatable{
void eat();
}
8.案例:多态数组
public class MyArray {
private int count;
//private String[] ds = new String[3];
private Jie head;
private Jie tail;
public void add(String s) {
count++;
Jie jie = new Jie(s);
// 判断头部 == null
if (head == null){
head = jie; // 让创建的车厢为头部(头节)
}else {
tail.next = jie; // 让这节跟在下一节
}
tail = jie; // 型车厢就是最后一节车厢
}
public int size() {
return count;
}
public String get(int i) {
Jie p = head;
for (int j = 0; j < i; j++) {
p = p.next;
}
return p.data;
}
// 私有内部类 只应用于该类,不想让别人用
private class Jie{
private String data;
private Jie next;
public Jie(String s) {
this.data = s;
}
}
}
复制public class Test {
public static void main(String[] args) {
/*
数组:数据个数是不会变化的
自定义一种数据结构:动态数组 链表式数据结构 使用引用
*/
MyArray datas = new MyArray();
datas.add("abc"); // 模拟的就是 数组[index] = 值;
//datas.add("123");
//datas.add("xgz");
datas.add("345");
//System.out.println(datas.add("erw"));
//System.out.println(datas.get(1));
for (int i = 0; i < datas.size(); i++) {// datas.size() 模拟的就是 数组.length
System.out.println(datas.get(i)); // 模拟数组,按下标取数据
}
}
}