java(五.一)--- 面向对象编程-继承

一、继承、

1、继承

public class inherit {
	public static void main(String[] args) {
			//Students S = new Students();
			//S.setName("Xiaohong");
			//System.out.println(S.getName());
			Scores Sc = new Scores();
			Sc.setName("Xiaohong"); //可以访问父类的setName()方法
			System.out.println(Sc.namess());  //
}

class Students{
	//private String name;  //用private 修饰的字段 name 和 age,无法被子类 Scores 访问,需将 private 换为 protected
	//private int age;
	protected String name;  //protected 修饰的字段可以被子类 Scores 访问
	protected String age;
	
public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return this.name;
	}
	
	public int getAge() {
		return this.age;
	}
}

class Scores extends Students{ //Scores 继承了 Studnets 类
	private int score;
	
	public String namess() {
		//return "Hello, " + name;
		//return "Hello, " + this.name;
		return "Hello, " + super.name;
	}
	public void setScore(int score) {
		this.score = score;	
	}
	public int getScore() {
		return score;
	}
}

输出
在这里插入图片描述
若 Scores 类中包括了 Students 类中的 name,age 字段,通过继承的方式,在 Score 类中就不用重复的写入 name,age 字段了,只需要在 Scores 类中添加新的字段 score;其中的 Students 类通常称之为超类 super class ,父类 parent class ,几类 base class;把 Scores 类称之为子类 subclass,扩展类 extended class

2、继承树

注意:在上面定义的时候,Students 没有写 extends, 在java 中没有明确写 extends 的类,编译器会自动加上 extends Object,所以任何类除了 Object,都会继承某个类,如下
在这里插入图片描述
在java继承中,一个类只一个父类,Object 类比较特殊没有父类

3、protected
在继承中子类无法访问父类的 private 字段或 private 方法,为了让子类可以访问父类的字段,我们需要把 private 改为 protected,用 protected 修饰的字段可以被子类访问

4、super
super关键字表示父类(超类),子类引用父类的字段时,可以使用 super.字段名

...skip...
public String namess() {
		//return "Hello, " + name;
		//return "Hello, " + this.name;
		return "Hello, " + super.name;
	}
...skip...

这里使用 super.name ,或者 this.name ,或者 name ,其实效果一样的;但是在某些情况下必须要使用 super 字段,如下面的例子

public class Superfield {
	...skip...
}
class Studentss{
	protected String name;
	protected int age;
	public Studentss(String name,int age) {
		this.name = name;
		this.age = age;
	}
...skip...
}
class Scoress extends Studentss {
	protected int score;
	public Scoress(String name, int age, int score){
		super(name,age); //调用父类构造函数
		this.score = score;
	}
}

如果父类没有默认的构造方法,子类就必须显示调用 supre()并给入参数以便让编译器定位到父类的一个合适的构造方法,这里顺带引出了一个问题:就是子类不会继承父类的构造方法,子类默认的构造方法是编译器自动生成的,不是继承的

5、向上转型
实际上就是把一个子类型安全地变为更加抽象的父类型

public class inherit {
	public static void main(String[] args) {
		//Students S = new Students();
		//S.setName("Xiaohong");
		//System.out.println(S.getName());
		Scores Sc = new Scores();
		Students S = Sc;
		S.setName("Xiaohong"); 
		System.out.println(Sc.namess());
		System.out.println(S.getName());
	}
}
class Students{
...skip...
}
class Scores{
	public String namess() {
		return "Hello, " + name;
	}
...skip...
}

输出:
在这里插入图片描述
6、向下转型
和向上转型相反,如果把一个父类类型强制转化为子类类型,就是向下转型

public class inherit {
	public static void main(String[] args) {
		Students S1 = new Scores(); //父类 Students S1 转为子类
		Scores F1 = (Scores) S1;
		S1.setName("Xiaohong");
		
		System.out.println(F1 instanceof Scores);   //true
		System.out.println(S1.getName()); //Xiaohong
	}
}

...skip...

向下转型时可能会失败,这时在向下转型时可以先进行判断,java中提供了 instanceof 操作符,来判断一个实例是不是某种类型,实际上是判断一个变量所指向的实例是否是指定类型,或者这个类型的子类;

...skip...
		Students S1 = new Scores();
		Scores F1 = (Scores) S1;
		Students S2 = null;
				
		System.out.println(F1 instanceof Students); //true
		System.out.println(S1 instanceof Scores); //true
		System.out.println(S2 instanceof Students); //false
...skip...

按理,如果在往下转型时可以添加判断

		Students S1 = new Scores();
		if (S1 instanceof Scores) {
			//只有判断成功才会向下转型
			Scores S2 = (Scores) S1;
			S2.setName("Xiaofang");
			System.out.println(S2.namess());  //Xiaofang
		}

7、区分继承和组合:从逻辑上讲,父类与子类的关系是 is 的关系,因此继承是 is 的关系

二、多态

1、多态

Override 与 Overload
在继承的关系中,子类如果定义了一个与父类方法相同的方法,被称之位覆盖(Override);如果方法签名不同,就是Overload,Overload是一个新的方法;如果方法签名相同,并且放回值相同,就是override

注意:
① 方法名相同,方法参数相同,但是方法返回值不同,也是不同的方法
② 什么是方法签名呢?
方法签名就是,方法名(类型 参数)

public class polymorphic {
	public static void main(String[] args) {
//...skip...
}
}
class Studentsss{
	public void abc() {
		System.out.println("123");
	}
}
class fScores extends Studentsss{
	@Override
	public void abc() {
		System.out.println("12123");
	}
}

@Override 不是必须的,在上面笔记中,引用变量声明的类型可能与实际类型不符

public class dasdf {
	public static void main(String[] args) {
		Mans M = new Peoples();
		M.names();   //2
		}
	}

class Mans{
	protected String names;
	
	public void names() {
		System.out.println("1");
	}
}

class Peoples extends Mans{ 
	
	@Override
	public void names() {
		System.out.println("2");
	}
}

上面中运行后发现调用的是 Peoples 中的 names() 方法,可以得出java的实例方法调用是基于运行时实际类型动态调用的,而非变量的声明类型,这个非常重用的特性在面向编程中称之为多态;而多态是指针对某个类型的方法调用,其正真执行的方法取决于实际类型的方法
对于多态的理解:简而言之就是,父类的对象变量调用了子类中的重写方法,需要注意的是,通常是自有一个父类,而他有多个子类,且在这些子类中同事重写父类的某个方法;多态的前提是有一个父类多个子类。

多态的简单理解: 如有游戏中,技能键,如按 R 的指令,在不同英雄或人物发出的技能效果就不一样
如:

public class dasdf {
	public static void main(String[] args) {
		
		Father F1 = new Father();
		
		Father F2 = new Sonone(); //前后两类型不同就产生了多态(就是说继承关系的类型,前者一定是后面的父类)
		Father F3 = new Sontwo();
		
		Sontwo S1 = new Sontwo();
		F1.names(); //1
		F2.names(); //2
		F3.names(); //3
		F3.newFunction(); //报错
		S1.newFunction(); //4
	}
}
class Father{
	protected String names;
	public void names() { 
		System.out.println("1");
	}
}

class Sonone extends Father{ 
	
	@Override
	public void names() { //重写父类方法
		System.out.println("2");
	}
}
class Sontwo extends Father{
	public void names() { //重写父类方法
		System.out.println("3");
	}
	public void newFunction(){
		System.out.println("4");
	}
}

覆写Object
因为所有的class最终都继承自Object,而Object,Object 定义了几个方法
toString() : 把instance输出为 String
equals(): 判断两个实例是否相等
hashCode:计算一个instance的哈希值
在必要的情况下覆写 Object 的这几个方法

public class Objectfuxie {
	public static void main(String[] args) {
		Object O = new Strkind();
		
		System.out.println(O.toString());
		System.out.println(O.equals(O));
		System.out.println(O.hashCode());
		
	}
}

class Strkind{
		public String name = "xianghong";
		@Override
		public String toString() {  //覆盖 Object中的 toString() 方法
			return "Name: " + name;
		}
		@Override
		public boolean equals(Object o){   //覆盖 Object 中的 equals() 方法
			if (o instanceof Strkind) {
				Strkind S = (Strkind) o;
				return this.name.equals(S.name);
			}
			return false;
		}
		@Override
		public int hashCode() {  //覆盖 Object 中的 hashCode() 方法
			return this.name.hashCode();
		}  
}

输出:
在这里插入图片描述
调用super
在子类的覆写方法中,如果调用父类的被覆写方法,需要通过 super 来调用

public class callsuper {
	public static void main(String[] args) {
		Fathers F = new Sons();
		F.steOne("abc");
		System.out.println(F.One());  //First abc!
	}
}
class Fathers{
	protected String onestr;
	public void steOne(String onestr) {
		this.onestr = onestr;
	}
	public String getOne() {
		return this.onestr;
	}
	public String One() {
		return "First " + getOne();
	}
}
class Sons extends Fathers{
	@Override
	public String One() {
		return super.One() + "!";
	} 
}

final
继承可以允许子类覆盖父类的方法,如果一个父类不允许子类对它的某个方法进行覆写,可以将该方法标记为 final;同理如果一个类不允许被继承那么 在类前 加一个 final 字段

不允许重写实例

class Father{
	public final sonfun(){}
}
class Sonone extends Fathers{
	@Override
	public final sonfun(){}  //报错不会允许被重写
}

不允许继承实例

final class Fathers{
...skip...
}

class Son extends Fathers{ //会报错
...skip...
}

注意: final修饰的field必须在创建对象时初始化,随后不可修改

三、抽象类

1、抽象类

由于多态存在,任意子类都可以重写父类的用一个方法,如果父类中一个被重写的方法没有意义,也不能去掉父类中被重写的方法,去掉的话失去多态的特性编译也会报错;如果父类的方法本身不需要实现任何功能。仅仅是为了定义方法签名,目的是让子类覆写他,那么只需要把父类的方法声明为抽象,声明的字段是; adstract

abstract class Fathers{
	public abstract void fun();
}

把一个方法声明为 abstract ,表示为一个抽象的方法,本身没有实现任何方法的语句。因为是抽象的无法执行,所以 上面的Fathers 类无法被实例化,所以必须把 Fathres 类本身声明为 abstract 。才能正确编译;注意无法实例化抽象的类,抽象类本身被设计成只能用于被继承,所以抽象类可以强迫子类实现其定义的抽象方法,否则编译就会报错

面向抽象编程

public class abstractclass {
	public static void main(String[] args) {
	//	Fathersss O = new Fathersss(); 
		Fathersss F = new Son();
		F.run();
		Sontwos S = new Sontwos();
		S.run();
	}
}
abstract class Fathersss{
	public abstract void run();
}

class Son extends Fathersss{
	@Override
	public void run() {
		System.out.println("Son.run");
	}
}

class Sontwos extends Fathersss{
	@Override
	public void run() {
		System.out.println("Sontwos.run");
	}
}

输出:
在这里插入图片描述

四、接口

1、接口
在抽象类中本质上是定义接口规范:就是规定高层的接口,从而保证所有子类都有相同的接口,这样,多态就可以发挥其作用
如果一个抽象类没有字段,所有方法全部都是抽象类方法,就可以把该抽象类改写为接口:interface
在java中可以使用 interface 声明一个接口

interface Father{
	viod run();
	String getName();
}

interface 就是比抽象类还要抽象的纯抽象接口,其中字段都不能有,接口定义的所有方法默认对都是 public abstract 的,所以这连个修饰符不需要写出来。
一个具体的 class 去实现一个interface 时,需要使用 implements 关键字。

interface的表示方式:

//声明了一个接口,这里的class不写
interface Fatherss{
	void run();
}
public class implement {
	public static void main(String[] args) {
		Fatherss F = new Sonss();
		F.run();
		
		Sonss S = new Sonss();
		S.world();
		S.run();
	}
}

interface Fatherss{
	void run();
}

interface Hello{
	void world();
}

class Sonss implements Fatherss,Hello{  //这里是一个类可以实现多个 interface
	@Override
	public void run() {
		System.out.println("OK!");
	}
	
	@Override
	public void world() {
		System.out.println("Hello World");
	}
}

输出:
在这里插入图片描述
这里是一个类可以实现多个 interface

2、接口继承(接口:interface)
一个 interface 可以继承自另一个 interface ,interface 继承自 interface 使用 extends,相当于拓展了接口方法

public class interfacess {
	public static void main(String[] args){
		C F= new C();
		
		F.setCstr("B");
		F.astr(); //A
		System.out.println(F.bstr()); //B
	}
}

interface A{
	void astr();
}

interface B extends A{ //interface B 继承了 interface A
	void astr();
	String bstr();
}

class C implements B{
	private String bstr;
	
	@Override
	public void astr() {
		System.out.println("A");
	}
	
	public void setCstr(String bstr) {
		this.bstr = bstr;
	}
	
	@Override
	public String bstr() {
		return this.bstr;
	}
} 

输出:
在这里插入图片描述
default 方法
接口中可以定义 default 方法

public class defaultmethod {
	public static void main(String[] args) {
		Sone F = new Sone();
		F.setName("Xiaohong");
		F.run();
	}
}
interface Fatherssss {
	String getName();
	default void run() {  //将 run() 方法改为 default 方法
		System.out.println("Go! " + getName()); //Go! Xiaohong

	}
}

class Sone implements Fatherssss{
	private String name;
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return this.name;

五、静态字段和静态方法

1、静态字段和静态方法
在一个class 中定义的字段,我们称之为实例字段,其特点是每个实例都有独立的字段,各个实例的同名字段互不影响;还有一种字段,使用 static 修饰的字段,这个就是静态字段; static 字段;

package classs;

public class statics {
	public static void main(String[] args) {
		Personss P = new Personss("Xiaohong ",13);
		//Personss P1 = new Personss("Xiaoming ",13);
		Personss.number = 123;
		System.out.println(P.name + P.age); 
		System.out.println(Personss.number); //123
		Personss.number = 321;
		System.out.println(Personss.number);
	}
}
class Personss{
	public String name;
	public int age;
	
	public static int number; //定义一个static修饰的静态字段
	
	public Personss(String name,int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return this.name;
	}
	public int getAge() {
		return this.age;
	}
}

输出:
在这里插入图片描述
静态方法
有静态字段就有静态方法,用 static 修饰的方法就是静态方法,调用实例方法必须通过一个是实例变量,而调用静态方法则不需要实例变量,通过类名就可以调用,静态方法类似其他编程语言的函数。

public class staticmothod {
	public static void main(String[] args) {
		Staticfun.setNumber(99); //直接调用,没有进行实例化
		System.out.println(Staticfun.number); //99
	}
}
class Staticfun{
	public static int number; //定义静态字段
	public static void setNumber(int value) { //定义静态方法
		number = value;
	}
}

因为静态方法属于 class 而不属于实例,因此,静态方法内部无法访问 this 变量,也无法访问是实例字段,只能方法静态字段,通过实例变脸也可以调用静态方法,但这只是编译器自动把实例改写成类名而已;如果太难过实例变量访问字段和静态方法,会有编译警告

接口静态字段
因为 interface 是一个纯抽象类,所以它能定义实例字段,但是,interface 是可以有静态字段的,并且静态字段必须是 final 类型;那么实际上,因为 interface 字段只能是 public static final 类型,所以我们可以把这修饰符去掉
未去掉时:

public interface Father{
	public static final int numberone = 1;
	public static final int numbertwo = 2;
}

可以简化为:

public interface Father{
	//编译器会自动加上:public static final
	int numberone = 1;
	int numbertwo = 2;
}

六、包/作用域

1、包

java中定义一个空间,就为包:package 。一个类总是属于某个包,真正完整的类名是 :包名.类名
在定义 class 的时候,我们需要在第一行声明这个 类 属于哪个包

package packageName; //申明包名
public class classname{
	...
}

在java虚拟机执行的时候,jvm只看完整的包名,所以包不同所以类就不同。包可以是多层次结构,,用 . 隔开,包是没有父子关系的

包的作用域
位于同一个包的类,可以访问报的作用域的字段和方法,在不用publc、protected、private 修饰的字段和方法就是包的作用域

import
在一个 class(类)中,我们总会引用其他 class(类),引用其他类的方法:
第一种就是直接写出完整的类名:PackageName.ClassName,这写起来繁琐;
第二种就是用 import 语句,导入完整的类名:import PackageName.ClassName;再使用时可以直接 写ClassName,在写import 的时候可以使用 * ,表示把这个报下的所有 class(类)都导入进来,但一般不推荐

第三种就是 import static 的语法,他可以导入一个类的静态字段和静态方法(很少用)
如:

package classs;

import static java.lang.System.*; // 导入System 类的所有字段和方法
public class importstatic {
	public static void main(String[] args) {
		out.println("123"); //相当于调用System.out.println(..)
	}
}

输出:
在这里插入图片描述

注意:
1、为了避免名字冲突,需要确定唯一的包名,推荐做法就是使用倒置的域名来确保唯一性。如:com.packagename,only
的形式
2、JDK的核心类使用 java.lang 包,编译器会自动导入,(所以直接使用了 System.out.println()…)

2、作用域

在java中,常见的 public、protected、private 修饰符,这些修饰符可以用来限定方位作用域

public
定义为 public 的 class、interface 可以被其他任何类访问

private
定义为 private 的 字段、方法无法被其他类访问,所以private访问权限被限定再class 的内部的,而且与方法声明的顺序无关。推荐把 private 方法放在后面,因为java中支持嵌套类,如果一个类内部还定义了嵌套类,那么,嵌套类拥有访问 private 的权限

protected
protected 作用域继承关系,定义的 protected 的字段和方法可以被子类访问,以及子类的子类

局部变量
在方法内部定义的变量成为局部变量,局部变量作用域从变量声明处开始到对应的块结束,方法参数也是局部变量

final
用 final 修饰的 class 可以阻止被继承,修饰的方法也不用被子类覆写,修饰的字段也不能被重新赋值,用final 修饰的局部变量可以阻止被重新赋值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值