java基础--面向对象三大特性(二)

5. 继承
优点:
	在一定程度上提高代码的复用性(将一些重复的内容不再多次编写)
关键字:
	extends
子承父业
	将多个类中的共性再一次抽取,作为一个父类。父类的作用就是
	用来讲一些重复的内容不再多次编写
注意事项:
	java中只支持单继承,一个子类有且只能有一个父类,复用性的提高		是有限的(多继承指的是A继承B,B又继承C)
	问题: 多继承好还是单继承好?
		单继承: 代码调用复杂度低,复用性有限
		多继承: 极大的提高代码复用性,但是代码调用的复杂度也提				升了	
	假设在应用场景中:
A->B 后期随着业务不断扩展,导致A需要继承C时一般的解决办法:A->B->C
但是该种解决办法随着后期业务的不断升级,导致整个继承连会变得极其复杂,既不利于后期维护以及拓展。能不能用继承就别用继承。
5.1 重写
定义:
	也叫方法覆盖,在子类中定义了和父类中同名的方法
为什么?
	父类的功能不能满足子类的需求,子类在父类的基础上进行扩展。
如何确定是重写?
	在子类方法上加上@Override注解,若不报错,则是重写。
重写前提:
	一定要发生继承关系,并且子类的方法名和父类的方法名相同(参数列表,返回类型相同)
5.2 Object
1. 是所有类的根基类,超类
2. 默认没写都是继承Object
3.输出一个对象的时候默认情况会调用当前对象的toString
 ==比较基本数据类型时,比较的是值,比较引用类型时,比较的是地址
 equals 用来比较相等的,如果相等返回true,
 4.object中比较是通过==比较的
6. 封装
1. public 	公共,都能访问被public修饰的方法、类和变量能被所有				类可见
2. Protected  同包下可见 异包下子类可见
3. 默认的   	不写的,同包可见异包不可见
4. private   	比较自私自利,本类可见
	范围自上而下依次变小

代码:

同包下的两个类(F是父类)
一、
package com.mage.opp.fu;
/**
 * 	四种修饰符
 */
public class F {
	public String name="张三丰";	//public修饰的
//	protected String name="张三丰";	//protected修饰的
//	private String name="张三丰";	//private修饰
	public static void main(String[] args) {
		F f = new F();
		System.out.println(f.name);
	}
}

二、
package com.mage.opp.fu;

public class LaoWang04 {
	public static void main(String[] args) {
		F f = new F();
		System.out.println(f.name);
		
	}
}



不同包下的二个类
一、
package com.mage.opp.fu;

public class LaoWang04 {
	public static void main(String[] args) {
		F f = new F();
		System.out.println(f.name);
		
	}
}

二、
package com.mage.opp.s;

import com.mage.opp.fu.F;

public class LaoWang03 extends F{

	public static void main(String[] args) {
		F f = new F();
		System.out.println("异包子类下的public:"+f.name);

	}

}

6.1 修饰变量
局部变量只能通过final修饰
1. 将类中的成员变量通过public、默认的、protected修饰之后导致某情况下可以随意.出来,这些修饰符修饰的变量不够安全。
2. 将这些变量通过private修饰。但是导致无法正常访问。
6.2 修饰方法
1. 修饰符的作用用来屏蔽一些底层的实现逻辑,降低调用者(程序员)的复杂度
2. 确保当前类更加安全,对外调用可以更加简单
3. 属性(成员变量)
		避免随意.属性,修改获取属性,造成数据不安全。
		如果用private,一定要保证对外提供get、set方法
		
7.多态
构成多态的前提:
		1. 存在继承关系
		2. 要有方法的重写
		3. 父类变量指向子类变量

代码:{//an.lookDoor();编译会出错[ 编译看左边(指对象an) 运行看右边(指方法lookDoor())]}

package com.mage.opp.duotai;

public class Test01 {
	public static void main(String[] args) {
		Animal an = new Bird();// 父类变量指向了子类对象
		an.shout();
		an.eat();	
		//an.lookDoor();编译会出错[ 编译看左边(指对象an)  运行看右边(指方法lookDoor())]
		
	}
}
class Animal{
	public Animal() {
		
	}
	public void shout() {
		System.out.println("animal shouting!");
		
	}
	public void eat() {
		System.out.println("animal eat!");
	}
	
}
class Bird extends Animal{
	public Bird() {
		
	}
	@Override
	public void eat() {
		System.out.println("重写了 Bird eat");
	}
	public void lookDoor() {
		System.out.println("看门");
	}
	
}
7.1 类的加载顺序
{ }代表代码块:
	1. 局部代码块:
			声明在方法中的
			缩减局部变量的生命周期,提高内存使用率
	2. 成员代码块:
			声明在方法外,是在类中的代码块
			初始代码块在类加载的时候是不会执行的
			在创建对象之前会被调用(对于对象中的一些初始进行初始				化操作)
	3. 静态代码块:
			声明在类中的,方法外,使用static修饰
			类加载的时候就会被加载,并且只加载一次 静态内容
执行顺序:
	1. 先执行静态内容(加载) 也就是静态代码块
	2. 初始化块
	3. 构造器
类加载:
	1. 当使用当前类中的静态方法、静态变量
	2. 当创建当前类的实例对象

代码:

package com.mage.opp.duotai;

public class Test02 {
	static{
		System.out.println("我是静态代码块");
	}
	int age;
	{
		 age = 20;
		System.out.println("我是初始化块(成员代码块)");
	}
	public static void main(String[] args) {
		{
//			int num = 10;
//			System.out.println("局部代码块中:"+num);
			Test02 t = new Test02();
			System.out.println(t.age);
			new Test02();
		}
	}
	public Test02() {
		System.out.println("我被调用了");
	}
}

图片

7.2 类型转换
引用类型也有类型转换:
 自动转换:
 	父类型 变量名 = 子类对象;【new 子类对象|子类对象的变量】
强制转换:
	子类型 变量名 = (子类型)父类变量; [事先确定了父类变量中实际存储的对象是什么类型]
	ClassCastException 类型转换异常
7.3 final
* final修饰的变量称之为最终常量,在程序运行期间其值不可发生改变
* final修饰的基本数据类型变量,无法进行修改,修饰引用类型时只是地址不会改变,对象中的内容还是会变化的(如下代码)
* final修饰的类不可以被继承(可以加太监类【无子类】)
* final修饰的方法不可以被重写

7.3.1 final面试题

final修饰静态常量经过方法

package com.mage.fina;

public class Test {
	//final static int num = 10;
	final static Bird bird = new Bird("麻雀","棕色");
	public static void main(String[] args) {
		
/*		fun(num);
		System.out.println("main方法中"+num);
*/	
		change();
	}
	public static void change() {
		bird.setColor("花色");
		//bird = new Bird(); 修饰的引用类型的变量 地址不变所以无法重新new同一个对象
		System.out.println("change中"+bird);
	}
	/*public static void fun(int num) {
		num++;
		System.out.println("fun方法中"+num);
		
	}
	*/
}
class Bird{
	private String name;
	private String color;
	public Bird() {
		
	}
	
	public Bird(String name,String color) {
		super();
		this.name = name;
		this.color = color;
	}
	@Override
	public String toString() {
		return "Bird [name=" + name + ", color=" + 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;
	}
	
	
}

final修饰的静态常量不会导致类加载

1. 静态成员常量不会导致类加载
2. 静态成员常量的值在加载前是无法确定的,就会导致类加载
两个类同时用,有联系的
一、
package com.mage.fina;

public class Test01 {
	//final static int num = 10;
	final static int num = (int)(Math.random()*12);
	static {
		System.out.println("我是静态代码块");
	}
	public static void main(String[] args) {
		System.out.println(Test01.num);
	}
}
二、
package com.mage.fina;

public class Test011 {
 public static void main(String[] args) {
	System.out.println(Test01.num);
}
}

8. abstract抽象类
1. 父类中定义的方法不需要具体的实现步骤,子类都不按照父类的做
2. 父类中定义的方法目的是要告诉子类一定要实现该类中的方法(也就是重写父类中的方法)
定义:
	包含了抽象方法的类称为抽象类
	被abstract修饰的类称为抽象类
抽象方法:
	只要方法的声明,没有方法体,通过abstract修饰的方法称之为抽象方法
	形式:
	abstract class Person{
		public abstract void eat() ;
	}
为什么需要抽象类?
	避免子类的随意设计 提高代码可读性,提高了子类的健壮性
	
	
abstract class Person{
	public abstract void eat() ;
}
class Chinese extends Person{
	public void eat() {
	}
}
class En{
	public void eat() {
	}
}
深入了解抽象类
	1. 抽象类中只能有抽象方法吗
		不是,既可以定义抽象方法也可以普通方法
	2.是否可以定义构造器呢
		可以,存在构造器但无法实例化,构造器只是给子类用的。
	3.抽象类就是用来被继承的,抽象方法就是被用来重写的,继承之后必须		重写所有的抽象方法。
package com.mage.opp.abstra;

public class Test03 {
	public static void main(String[] args) {
		//Animal an = new Animal(); 无法进行实例化所以报错
		Bird bird = new Bird();
		bird.eat();
	}
}
abstract class Animal{
	public Animal() {
		System.out.println("我是抽象类的构造器");
	}
	public abstract void eat();
	
}
class Bird extends Animal{
	public Bird() {
		
	}
	public void eat() {
		System.out.println("我重写了抽象类中的方法");
	}
}
8.1 模板方法
模板方法:
	1. 将上下文中的一些不会变化的内容保留下来 在父类中实现
	2. 并且定义整个程序的执行流程
	3. 将核心的业务逻辑或者是算法逻辑延迟到子类中去实现。
		喝茶 烧水 冲泡 干了
		喝咖啡 烧水 搅拌 干了
package com.mage.oop.abstrac;

public class Test03 {
	public static void main(String[] args) {
		/*
		 * Tea t = new Tea(); t.flow();
		 * 
		 * Caf c = new Caf(); c.flow();
		 */
		Water w1 = new Tea();
		w1.flow();
		Water w2 = new Caf();
		w2.flow();
		
		
	}
}

abstract class Water{
	private void fireWater() {
		System.out.println("咕噜咕噜咕噜");
	}
	
	public abstract void pp() ;
	
	private void drink() {
		System.out.println("墩儿~墩儿~墩儿~墩儿~");
	}
	
	public void flow() {
		fireWater();
		pp();
		drink();
	}
	
}

class Tea extends Water{
	
	public void pp() {
		System.out.println("冲泡");
	}
	
}
class Caf extends Water{
	
	
	public void pp() {
		System.out.println("搅拌");
	}
	
}


9. 接口
接口是一个规范 是一套标准 比抽象类还要抽象
 Tips:
    接口就是一套规则,用来定义具体要做哪些事情,但是所有事情的具体实	现都会延迟到实现类中完成。接口只
    需要定义has-a的关系,如果你是什么,则你具备了什么能力。
    学习接口和学习类是一样的
形式:
	修饰符 interface 接口名{}
1. 接口中的变量是公开的(要被其他类使用) 静态的最终常量值 默认情况下变量都是public static final修饰的,如下代码
 int SPEED = 10;默认是public final static int SPEED = 10;
2.接口中可以定义静态方法(1.8版本后不建议用)
3. 接口中定义的对象方法都是抽象方法(因为比抽象类还要抽象),接口中的方法默认就是通过abstract修饰的
4.接口中默认方法从1.8之后才开始使用,允许在接口中定义default方法,而且存在方法体
interface A{
 
 int SPEED = 10;
 
 default void method() {
  
  }
 public static void fun1() {
 
  }
  public abstract void fun2() ;
  
 }
9.1 深入了解接口
形式:
	修饰符 class 类名 extends 父类 implements 接口
1. 类和接口直接通过implements发生关系,类实现接口
2. 类必须实现接口中所有抽象方法
3. 可以实现多个接口,类名 implements 接口1,接口2...
4. 一个类实现了接口之后,要将当前接口及接口的父接口中的所有抽象方法全部重写
5. 接口可以多继承
6. 接口无法实例化
7. 接口没有构造器
8. 接口中也可以使用多态
equals
equals方法就是用来比较两个对象是否相等的,默认Object的equals方法比较是两个对象的地址。
java.lang.NullPointerException 空指针异常 对象为null
  	ClassCastException 类型转换异常
	null可以强转为任意类型 null也可以是任意类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值