编程语言
首页 > 编程语言> > Java第九课. 接口&修饰符

Java第九课. 接口&修饰符

作者:互联网

Java第九课. 接口&修饰符

回顾

抽象方法&抽象类
1. 当这个方法没有办法写具体的实现的时候就需要定义为抽象类;
2. 使用关键字 abstract 修饰的方法就称为抽象方法,没有方法体,没有具体实现;
3. 一个抽象类中可以包含抽象方法和普通方法, 如果一个类中包含一个以上的抽象方法,这个类就必须定义为抽象类;
4. 抽象类中有构造方法,不能用 abstract 修饰,不能直接实例化,父类只能被继承,由子类进行实例化:向上转型:父类 父引用=new 子类();此时,父类的引用可以调用[父类的属性和方法+子类和父类的共有的属性和方法];
5. 一个类继承了抽象类,就必须重写父类的所有抽象方法,如果不重写,该子类也必须定义为抽象类;

1. 接口

1.1 接口引入

[引出问题]:一个人多角色:演员,歌手,每一个角色都是一个类,能否让人去继承每一个角色的类;否
[出现问题]:java中类是单继承,不能同时继承歌手和演员类;
[解决问题]:将角色定义成接口,让类去实现多个接口,java中的接口是支持多继承的;

1.1 接口的定义

接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是[抽象方法的集合],接口通常以 interface 来声明;一个类通过继承接口的方式,从而来继承接口的抽象方法;
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
定义一个接口: 修饰符[public]  interface 接口名[I类似类名]{
     //公共常量  public static final 数据类型 常量名[大写] = 值;
     //抽象方法
     //默认方法/静态方法[jdk1.8才有,低于1.8是不能出现默认方法的]
}

继承的写法: extends
interface 接口名 extends 接口1,接口2{
}
implements 实现
class  类名 implements 接口1,接口2{
}

[注意]:
1. 类之间用继承,接口之间也可以用继承;但类和接口之间用实现;
2.一个类可以同时继承和实现接口:继承放在前面;
3.接口里面常量默认用大写,用public static final修饰;
/**
 * 演员
 * @author Administrator
 *
 */
public interface IActor {
	//演戏抽象方法
	//public abstract void perform(String something);
	// abstract void perform(String something);
	void perform(String something);//简写
	
	//公共常量
	//public static final int N=1;
	//static final int N=1;
	// final int N=1;
	int N=1;//简写
	
	//Default methods are allowed only at source level 1.8 or above
    //默认方法
	default void test() {
		System.out.println("我是default方法,我在jdk1.8中不会出错");
	}
	
}

/**
 * 歌手
 * @author Administrator
 *
 */
public interface ISinger {

	void sing(String song);
}
public class SomeBody extends Object implements IActor,ISinger{
	private String name;

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public void perform(String something) {
		System.out.println(name+"请开始表演"+something);
		
	}
	@Override
	public void sing(String song) {
		System.out.println(name+"开唱"+song);
	}

}
测试类:
public class TestSomebody {

	public static void main(String[] args) {
		SomeBody someBody=new SomeBody();
		someBody.setName("刘德华");
		
		someBody.perform("拆弹专家");
		someBody.sing("忘情水");
	}

}

刘德华请开始表演拆弹专家
刘德华开唱忘情水
    
//注意:接口的定义,接口中包含的内容,接口支持多继承的写法;

1.2 [面试题]抽象类和接口的区别

1. 抽象类使用 abstract 关键字进行修饰,而接口使用 interface 进行定义;
2. 抽象类只支持单继承,接口可以支持多继承;
3. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的[静态常量];
4. 抽象类可以有抽象方法和普通方法,也可以有变量和常量,可以有构造方法;
5. 接口中可以包含抽象方法和静态常量,如果是jdk1.8的话,可以包含默认方法和静态方法,没有构造方法;

1.3 多态再说明

1.31 实现方式
1.[编译时多态]:对象和方法在程序运行之前就已经确定了,执行的时候不会存在动态判断的情况了,这种称为编译时多态; 实现方式就是方法的重载;
    Class Pig{
        Public void eat(){
            Sysout(“吃猪食”);
    	}
        Public void eat(String food){ //面包
            Sysout(“吃”+food);
        }
        Public void eat(String food,String drink){ //面包 茅台
            Sysout(“吃”+food+”,配…”+drink); //
        }
}
2.[运行时多态]使用[继承]: 创建父类 ,创建子类,在子类中重写父类的方法,应用场景中将父类作为参数传递,实际调用的传递具体的对象(子类对象) ,那么实际执行的时候,根据不同的子类对象来执行特定子类的方法;
3.[运行时多态]使用[接口来实现]: 创建父接口,创建接口的实现类;在实现类中实现接口中的抽象方法,应用场景中将父接口作为参数,实际调用的时候传递具体的实现类的对象, ,那么实际执行的时候,根据不同的子类对象来执行特定子类的方法;
1.32 优点
[可替换性](substitutability)
	多态对已存在代码具有可替换性;
[可扩充性](extensibility)
	多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能;
[接口性](interface-ability)
	多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的;
[灵活性](flexibility)
	它在应用中体现了灵活多样的操作,提高了使用效率;
[简化性](simplicity)
	多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要;

1.4 练习

模拟USB接口的工作: USB是一个接口,键盘、鼠标、U盘都可以插在USB接口上 ;创建一个计算机,安装设备,让这个设备工作就可以了; 
public interface Usb {
	//检测方法
	void Checkout();
    //处理方法
	void Handle(String something);

}
public class KeyBoard implements Usb {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public void Checkout() {
		System.out.println("检测到"+name+"设备");
		
	}

	@Override
	public void Handle(String something) {
		System.out.println(something+name);
		
	}


}
public class Mouse implements Usb {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public void Checkout() {
		System.out.println("检测到"+name+"设备");
		
	}

	@Override
	public void Handle(String something) {
		System.out.println(something+name);
		
	}

}
public class Ufd implements Usb {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public void Checkout() {
		System.out.println("检测到"+name+"设备");
		
	}

	@Override
	public void Handle(String something) {
		System.out.println(something+name);
		
	}

}
public class TestComputer {

	public static void main(String[] args) {
		
		Computer1 computer=new Computer1();
		
		KeyBoard keyBoard=new KeyBoard();
		keyBoard.setName("键盘");
		computer.install(keyBoard);
		
		Mouse mouse=new Mouse();
		mouse.setName("鼠标");
		computer.install(mouse);
		
		Ufd ufd=new Ufd();
		ufd.setName("U盘");
		computer.install(ufd);

	}

}

检测到键盘设备
运行键盘
检测到鼠标设备
运行鼠标
检测到U盘设备
运行U盘

2. 修饰符

2.1 访问修饰符

1. 作用:在Java中实现信息隐藏的是访问控制权限机制;    
   访问控制权限包括 4个访问修饰符: public 、 protected 、缺省 和 private 。
2. 权限如下:
    1.public: 不受任何限制,本类或非本类均可随意访问 (公开的,谁都可以调,可跨包,全友好);
    2.protected:同一个包中的其它类也可访问(同包友好);
    本类及其子类可以访问:允许不同包中的子类访问父类的保护方法和保护属性。(跨包父子友好)
	3.缺省(不使用任何修饰符):只有相同包中的类可以访问。(同包友好) 
	4.private:只有本类可以访问,其余都不可以。(本类友好)
//对类使用的访问修饰符只有public和缺省两种,对成员的修饰符四个都可以。

在这里插入图片描述
在这里插入图片描述

2.2 非访问修饰符-三大关键字

2.21 抽象:abstract
1. 一个类中只要有一个或一个以上抽象方法,必须用 abstract 声明为抽象类; 
2. 抽象类中可以有具体的实现方法,也可以没有抽象方法; 
3. 抽象类中的所有的抽象方法必须被它的子类实现,如果子类没有实现,则该子类继续为抽象类 
4. 抽象类不能被直接实例化,但可以由抽象父类指向的子类实例来调用抽象父类中的具体实现方法;通常作为一种默认行为; 
5. 要使用抽象类中的方法,必须有一个子类继承于这个抽象类,并实现抽象类中的抽象方法,通过子类的实例去调用; 
2.22 最终的:final
1. 可用于修饰:成员变量,非抽象类(不能与 abstract 同时出现),非抽象的成员方法,以及方法参数 ;
2. final 类:[表示该类不能被继承,没有子类];
3. final 方法:[不能被子类的方法重写,但可以被继承]; 
4. final 变量:[表示常量,只能赋值一次,赋值后不能被修改;final 变量必须定义初始化]; 
5. final 参数:只能使用该参数,不能修改该参数的值; 
6. final 不能用于修饰构造方法;

在这里插入图片描述

2.23 静态:static
class 类{
       static int a;           //静态变量
       static void method();  //静态方法
       static{...}           //静态块
}
[静态变量与静态方法]:数据存放的位置与普通变量方法不同;存放在class文件中指的是你程序运行之前就已经存进去数据了;
[普通变量与普通方法]:程序运行后才生成堆栈中;
1. static 修饰的成员变量它不依赖类特定的实例,被类的所有实例[共享],在内存中唯一;

在这里插入图片描述
在这里插入图片描述

2. static 变量和 static 方法一般是通过类名直接访问,但也可以通过类的实例来访问(不推荐这种访问方式)  

在这里插入图片描述

3. 非静态的方法中可以[访问(调用)]静态方法和静态变量,但是静态方法中不能访问非静态方法和非静态变量;

static 修饰的方法可以被普通方法用 类.方法名()调用,但普通方法不能被 static 修饰的方法调用,必须要使用对象.方法名来用;
static 修饰的方法也可以被 static 修饰的方法 类.方法名()调用;
同一个类中,两个都是 static 修饰或者都没有用 static 修饰的方法可以相互直接调用;
4. [静态块]:在程序运行过程中,[最早执行]:初始化 static 修饰的成员时,可以将他们统一放在一个以 static 开始,用花括号包裹起来的块状语句中。

在这里插入图片描述

5.	static 不能修饰主类以及构造方法;
    JAVA中静态的东西都是属于类的,为类服务,构造函数是为了初始化对象,为对象服务。构造函数是用来生成实例,既然是实例就不是  static 的;
6. 用 public 修饰的 static 变量和 static 方法,在任何地方都可以通过类名直接来访问,但用 private 修饰的 static 变量和 static 方法,只能在声明的本类方法及静态块中访问,在静态块不能用 this 访问,因为 this 属于非静态变量;
[问题]:为什么java中的 static 类不用实例化就可以直接调用方法?
    
因为加了 static 关键字的变量或者方法是属于类的,在程序加载类的字节码的时候就加载到一个静态内存区域属里面去了,而且一直在程序运行中存在,不会随着方法的调用结束而消失。所以是直接通过类名调用的 它属于类,不属于实例对象;
[注意]:没有构造方法的类都是由static修饰它的方法;
2.3 三个关键字混搭使用:
1. static 和 final [可以同时]使用 ;
   1. static final 用来修饰成员变量和成员方法,可简单理解为“全局常量”! 
   2. 对于变量,表示一旦给值就不可修改,并且通过类名可以访问。 
   3. 对于方法,表示不可重写,并且可以通过类名直接访问。
2. 为什么[不能同时]加 abstract 与 static 呢?
static 是静态的,就是在编译时已经是确定的东西,不能是抽象的。
因为 static 修饰的方法是静态方法,其可以直接被类所调用。而 abstract 修饰的方法为抽象方法,即无方法体的方法,不能够被直接调用,需要在子类或实现类中去编写完整的方法处理逻辑后才能使用。
3. 为什么[不能同时]加 abstract 与 final 呢?
因为final是最终的,不可以被继承,不可以被重写。
而abstract是抽象的,只能被继承,被重写。

应用广泛: 将某一个不会修改的变量设置为静态常量 public static final String username ="root"

3. 练习

3.1 面向对象综合题:猜拳游戏-人机
1.创建玩家类Player:用户名name、积分score、抽象方法:出拳方法showFist()
2.创建人Person和电脑Computer分别实现玩家类,实现抽象方法出拳 Math.random()
3.创建Game类:pk()方法  获取随机数对应中文:1石头 2剪刀 3布
4.测试类:

    显示结果如下:
        玩家阿杜 出拳:石头
        电脑AI   出拳:布
        恭喜你:AI

public abstract class Player {
	/**
	 * 属性:用户名,积分
	 */

	private String name;
	private int score;
	/**
	 * getter与setter
	 * @return
	 */
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
	/**
	 * 有参构造
	 * @param name
	 * @param score
	 */
	public Player(String name, int score) {
		super();
		this.name = name;
		this.score = score;
	}
	/**
	 * 无参构造
	 */
	public Player() {
		// TODO Auto-generated constructor stub
	}
	/**
	 * 抽象方法:出拳
	 */
	public abstract int showFist();
}
import java.util.Scanner;

public class Person extends Player{

	@Override
	public int showFist() {
		System.out.println("请输入1石头 2剪刀 3布");
		Scanner scanner=new Scanner(System.in);
		int fist=scanner.nextInt();
		return fist;
		
	}
	public Person() {
		// TODO Auto-generated constructor stub
	}
	/**
	 * 有参构造
	 */
	public Person(String name,int score) {
		//传递给父类
		super(name,score);
	}

}
import java.util.Random;

public class Computer extends Player {

	@Override
	public int showFist() {
		Random random=new Random();
		int fist=random.nextInt(3)+1;//范围0~2 +1:1~3
		return fist;
	}
	public Computer() {
		// TODO Auto-generated constructor stub
	}
	/**
	 * 有参构造
	 */
	public Computer(String name,int score) {
		//传递给父类
		super(name,score);
	}

}
public class Game {
	/**
	 * 定义2个成员变量 ,让类中所有方法共用
	 */

	private Person p;
	private Computer c;


	/**
	 * 通过构造方法将2个对象传递进来
	 */
	public Game(Person p, Computer c) {
		super();
		this.p = p;
		this.c = c;
	}
	/**
	 * 人和电脑pk
	 */
	public void pk() {
		//提升1:加入循环  5局
		for (int i = 1; i <=5; i++) {
			System.out.println("第"+i+"局开始:");
			//人的出拳  数字
			int pFist=p.showFist();
			//电脑的出拳  数字
			int cFist=c.showFist();

			//提升2: 出拳以中文显示
			//人的中文
			String pvalue=getFistValue(pFist);
			//电脑的中文
			String cvalue=getFistValue(cFist);
			//判断
			if (pFist<=3 && pFist>=1) {
				//让用户赢
				if (pFist==1 && cFist==2 || pFist==2 && cFist==3 || pFist==3 && cFist==1) {
					System.out.println(p.getName()+"出拳:"+pvalue);
					System.out.println(c.getName()+"出拳:"+cvalue);
					System.out.println("人:"+p.getName()+"恭喜你赢了!!!");
					System.out.println("-----------------------------");
					//提升3:加积分,用户积分+1
					p.setScore(p.getScore()+1);//先取出来+1再重新赋值

				}else if (pFist==cFist) {//平局
					System.out.println(p.getName()+"出拳:"+pvalue);
					System.out.println(c.getName()+"出拳:"+cvalue);
					System.out.println("平局");
					System.out.println("-----------------------------");
				}else {//电脑赢
					System.out.println(p.getName()+"出拳:"+pvalue);
					System.out.println(c.getName()+"出拳:"+cvalue);
					System.out.println("电脑:"+c.getName()+"恭喜你赢了!!!");
					System.out.println("-----------------------------");
					//提升3:加积分,电脑积分+1
					c.setScore(c.getScore()+1);
				}

			}else {
				System.out.println("请重新出拳:");
				//提升4:当前这局重新开始
				i--;//带值进去理解
				continue;
			}
		}
		//5局比较完(循环结束)显示最终结果
		showResult();

	}

	/**
	 * 
	 * 将数字变成中文的出拳方式
	 * @param  出拳的数字格式
	 * @return 返回中文
	 */
	public String getFistValue(int fist) {
		String string="";
		switch (fist) {
		case 1:
			string="石头";
			break;
		case 2:
			string="剪刀";
			break;
		case 3:
			string="布";
			break;
		default:
			break;
		}
		return string;
	}
	
	/**
	 * 显示最终结果
	 */
	public void showResult() {
		System.out.println("-----------显示最终结果:-----------");
		System.out.println(p.getName()+"获取积分:"+p.getScore());
		System.out.println(c.getName()+"获取积分:"+c.getScore());
		if (p.getScore()>c.getScore()) {
			System.out.println(p.getName()+"在5局中获胜!!");
		}else if (p.getScore()==c.getScore()) {
			System.out.println("平局");
		}else {
			System.out.println(c.getName()+"在5局中获胜!!");
		}
	}
}
/**
 * 测试类
 * @author Administrator
 *
 */
public class TestGame {

	public static void main(String[] args) {
		//使用有参构造方法传递姓名个积分
		Person person=new Person("君扬", 0);
		Computer computer=new Computer("007",0);

		Game game=new Game(person, computer);
		game.pk();
	}

}

在这里插入图片描述

标签:Java,String,修饰符,接口,static,第九课,方法,public,name
来源: https://blog.csdn.net/zhuang15/article/details/111188054