JavaSE面向对象编程下

关键字:static

static关键字的使用

static:静态的

static可以用来修饰:属性 方法 代码块 内部类

使用static修饰属性:静态变量(类变量)

  • 属性:按照是否使用static修饰,分为 静态变量 vs 非静态变量(实例变量)
  • 实例变量:创将类的多个对象,每个对象都独立拥有一套类中的实例变量,当修改其中一个对象的实例变量时,不会导致其他对象中同样的实例变量值发生修改
  • 静态变量:创将类的多个对象,多个对象都共享静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,发生修改

static修饰属性的其他说明:

  • 静态变量随着类的加载而加载,可以通过"类.静态变量"的方式进行调用
  • 静态变量的加载要早于对象的创建
  • 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在于方法区的静态域中
是否可以调用类变量实例变量
yesno
对象yesyes

类变量 vs 实例变量的内存解析
在这里插入图片描述

使用static修饰方法: 静态方法

  • 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
是否可以调用静态方法非静态方法
yesno
对象yesyes
  • 静态方法中,只能调用静态的方法或属性
  • 非静态方法中,既可以调用非静态的方法或属性,又可以调用静态的方法或属性

static注意点:

  • 在静态的方法内,不能使用this,super关键字
  • 关于静态属性和静态方法的使用,可以从生命周期的角度去理解

开发中,如何确定一个属性是否声明为static的?

  • 属性是可以被多个对象所共享的,不会随着对象的不同而不同的
  • 类中的常量也经常声明为static

开发中,如何确定一个方法是否声明为static的?

  • 操作静态属性的方法,通常设置为static的
  • 工具类中的方法,习惯上声明为static的,比如Math,Arrays
package com.atguigu.chapter6;

public class StaticTest {
	public static void main(String[] args) {
		
		Chinese.nation = "中国";
		
		Chinese c1 = new Chinese();
		c1.name = "姚明";
		c1.age = 40;
		c1.nation = "CHN";
		
		Chinese c2 = new Chinese();
		c2.name = "马龙";
		c2.age = 30;
		c2.nation = "china";
		System.out.println(c1.nation);
		
		//编译不通过
		//Chinese.name = "张继科";
		
		Chinese.show();
		c1.eat();
		c1.show();
		
		//编译不通过
		//Chinese.eat();
		
	}
}

class Chinese{
	
	String name;
	int age;
	static String  nation;
	
	public void eat() {
		System.out.println("中国人吃中餐!");
		show();
	}
	
	public static void show() {
		System.out.println("自信即巅峰!");
		System.out.println(Chinese.nation);
	}
}

static关键的应用

package com.atguigu.chapter6;

public class CircleTest {
	public static void main(String[] args) {
		Circle c1 = new Circle();
		
		Circle c2 = new Circle();
		
		System.out.println("c1的ID:" + c1.getID());
		System.out.println("c2的ID:" + c2.getID());
		
		System.out.println("创建圆的个数:" + Circle.total);
	}
}

class Circle{
	private double radius;
	private int ID;
	
	public static int total;//记录创建圆的个数
	public static int init = 1001;//static声明的属性被所有对象共享
	
	
	public Circle() {
		ID = init++;
		total++;
	}
	
	
	public double getRadius() {
		return radius;
	}


	public void setRadius(double radius) {
		this.radius = radius;
	}


	public int getID() {
		return ID;
	}


	public void setID(int iD) {
		ID = iD;
	}


	public double findArea() {
		return 3.14*radius*radius;
	}
}

static 课后练习

编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额”、“利率”、“最小余额”,定义封装这些属性的方法。账号要自动生成。编写主类,使用银行账户类,输入、输出3个储户的上述信息。
考虑:哪些属性可以设计成static属性。

package com.atguigu.chapter6;

public class Account {
	private int id;
	private String password = "123456";
	private double balance;
	
	private static double interestRate;
	private static double minMoney = 1.0;
	
	private static int init = 1001;
	
	public Account() {
		this.id = init++;
	}
	
	public Account(String pwd,double balance) {
		this.id = init++;
		this.password = pwd;
		this.balance = balance;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public static double getInterestRate() {
		return interestRate;
	}

	public static void setInterestRate(double interestRate) {
		Account.interestRate = interestRate;
	}

	public static double getMinMoney() {
		return minMoney;
	}

	public static void setMinMoney(double minMoney) {
		Account.minMoney = minMoney;
	}

	public int getId() {
		return id;
	}

	public double getBalance() {
		return balance;
	}

	@Override
	public String toString() {
		return "Account [id=" + id + ", password=" + password + ", balance=" + balance + "]";
	}
	
	
}

package com.atguigu.chapter6;

public class AccountTest {
	public static void main(String[] args) {
		Account acct1 = new Account();
		Account acct2 = new Account("qwertyuiop",2000);
		
		Account.setInterestRate(0.045);
		Account.setMinMoney(500);
		
		System.out.println(acct1);
		System.out.println(acct2);
	}
}

单例 (Singleton)设计模式

设计模式在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱。

类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。

如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的

如何实现类的单例设计模式?

饿汉式 vs 懒汉式

package com.atguigu.chapter6;

public class SingletonTest1 {
	public static void main(String[] args) {
		Bank bank1 = Bank.getInstance();
		Bank bank2 = Bank.getInstance();
		
		System.out.println(bank1 == bank2);//true
		
	}
}

//饿汉式
class Bank{
	
	//1.私有化类的构造器
	private Bank() {
		
	}
	
	//2.内部创建类的对象
	//4.要求此对象也必修声明为静态的
	private static Bank instance = new Bank();
	
	//3.提供公共的静态方法,返回类的对象
	public static Bank getInstance() {
		return instance;
	}
	
}
package com.atguigu.chapter6;

public class SingleTest2 {
	public static void main(String[] args) {
		Order o1 = Order.getInstance();
		Order o2 = Order.getInstance();
		
		System.out.println(o1 == o2);//true
	}
}

//懒汉式
class Order{
	
	//1.私有化类的构造器
	private Order() {
		
	}
	
	//2.声明当前类的对象
	//4.此对象也必须声明为static
	private static Order instance = null;
	
	//3.声明public , static 的返回当前类对象的方法
	public static Order getInstance() {
		if(instance == null) {
			instance = new Order();
		}
		
		return instance;
	}
}

区分 懒汉式 和 饿汉式

饿汉式

  • 好处:饿汉式是线程安全的
  • 坏处:对象加载时间过长

懒汉式

  • 好处:延迟对象的创建
  • 坏处:目前的写法坏处:线程不安全 —> 到多线程内容在改

单例模式的优点

由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决

可以在 网站的计数器, 应用程序的日志应用,数据库连接池的设计,项目中,读取配置文件的类 等方面去使用

理解main方法的语法

  • main() 方法作为程序的入口
  • main() 方法也是一个普通的静态方法
  • main() 方法可以作为我们与控制台交互的方式
package com.atguigu.chapter6;

public class MainTest {
	public static void main(String[] args) {
		Main.main(new String[10]);
		MainTest t1 = new MainTest();
		t1.show();
	}
	
	public void show() {
		System.out.println("自信即巅峰!");
	}
	
	
}

class Main {
	public static void main(String[] args) {

		for (int i = 0; i < args.length; i++) {
			args[i] = "args_" + i;
			System.out.println(args[i]);
		}
	}
}

类的成员之四:代码块

类的成员之四:代码块(或初始化块)

  • 代码块的作用:用来初始化类,对象
  • 代码块如果有修饰的话,只能使用 static
  • 分类:静态代码块 vs 非静态代码块
  • 静态代码块
    内部可以有输出语句
    随着类的加载而执行,而且只执行一次
    作用:初始化当前类的信息
    如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
    静态代码块的执行要优于非静态代码块的执行
    静态代码块内部只能调用 静态的属性,方法
  • 非静态代码块
    内部可以有输出语句
    随着对象的创建而执行
    每创建一次对象,就执行一次非静态代码块
    作用:可以在创建对象时,可以对对象属性等进行初始化
    如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
    非静态代码块内部调用 静态的属性,方法,还可以调用非静态属性,方法
package com.atguigu.chapter6;

public class BlockTest {
	public static void main(String[] args) {
		String desc = Person.desc;
		System.out.println(desc);
		Person p1 = new Person();
	}
}

class Person{
	String name;
	int age;
	static String desc = "我是人!";
	
	public Person() {
		
	}
	
	public Person(String name,int age) {
		this.name = name;
		this.age = age;
	}
	
	//static代码块
	static{
		desc = "我需要努力,锤爆华宝的狗头";
		System.out.println("hello,static block1");
	}
	static{
		desc = "我需要努力,锤爆华宝的狗头";
		System.out.println("hello,static block2");
		info();
	}
	
	//非static代码块
	{
		age = 1;
		System.out.println("hello,block");
		desc = "怒搓华宝狗头";
		info();
		eat();
	}
	
	public void eat() {
		System.out.println("吃饭!");
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
	public static void info() {
		System.out.println("果断大胆自信!");
	}
	
}

代码块的课后习题

package com.atguigu.chapter6;

//由父及子  静态先行  非静态代码块 > 构造器
class Root{
	static{
		System.out.println("Root的静态初始化块");
	}
	{
		System.out.println("Root的普通初始化块");
	}
	public Root(){
		System.out.println("Root的无参数的构造器");
	}
}
class Mid extends Root{
	static{
		System.out.println("Mid的静态初始化块");
	}
	{
		System.out.println("Mid的普通初始化块");
	}
	public Mid(){
		System.out.println("Mid的无参数的构造器");
	}
	public Mid(String msg){
		//通过this调用同一类中重载的构造器
		this();
		System.out.println("Mid的带参数构造器,其参数值:"
			+ msg);
	}
}
class Leaf extends Mid{
	static{
		System.out.println("Leaf的静态初始化块");
	}
	{
		System.out.println("Leaf的普通初始化块");
	}	
	public Leaf(){
		//通过super调用父类中有一个字符串参数的构造器
		super("尚硅谷");
		System.out.println("Leaf的构造器");
	}
}
public class LeafTest{
	public static void main(String[] args){
		new Leaf(); 
		//new Leaf();
	}
}


//结果
Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:尚硅谷
Leaf的普通初始化块
Leaf的构造器

package com.atguigu.chapter6;

//由父及子  静态先行  非静态代码块 > 构造器
//main()方法也是一个静态方法 
class Father {
	static {
		System.out.println("11111111111");
	}
	{
		System.out.println("22222222222");
	}

	public Father() {
		System.out.println("33333333333");

	}

}

public class Son extends Father {
	static {
		System.out.println("44444444444");
	}
	{
		System.out.println("55555555555");
	}
	public Son() {
		System.out.println("66666666666");
	}


	public static void main(String[] args) { // 由父及子 静态先行
		System.out.println("77777777777");
		System.out.println("************************");
		new Son();
		System.out.println("************************");

		new Son();
		System.out.println("************************");
		new Father();
	}

}

//结果
11111111111
44444444444
77777777777
************************
22222222222
33333333333
55555555555
66666666666
************************
22222222222
33333333333
55555555555
66666666666
************************
22222222222
33333333333

对属性赋值的先后顺序 完结版

(从前往后)默认初始化 — 显示初始化 / 代码块赋值 ----- 构造器赋值 ---- 对象.属性 或者 对象.方法

关键字:final

final:最终的

final可以用来修饰的结构:类,变量,方法

final用来修饰一个类:此类不能被其他类所继承
比如:String类,System类,StringBuffer类

final用来修饰一个方法:表明此方法不能被重写
比如:Object类中getClass()方法

final用来修饰一个变量:此时的"变量"就称为是一个常量|

  • final修饰属性:可以考虑赋值的位置有:显示初始化,代码块,构造器
  • final修饰局部变量:
    尤其是final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参,一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

static final 用来修饰属性:全局常量

final关键字的测试题

public class Something {
	public int addOne(final int x) {
		//return ++x; 编译错误 x被重新赋值
		return x + 1;//编译通过
	}
}
package com.atguigu.chapter6;

public class Something {
	public static void main(String[] args) {
		Other o = new Other();
		new Something().addOne(o);
	}

	public void addOne(final Other o) {
		// o = new Other(); 加这一行语句,编译错误
		o.i++;
	}
}

class Other {
	public int i;
}

抽象类与抽象方法

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类

abstract关键字的使用

abstract:抽象的

abstract可以用来修饰的结构:类 方法

abstract修饰类:抽象类

  • 此类不能实例化
  • 抽象类中一定有构造器,便于子类实例化中调用(涉及:子类对象实例化的全过程)
  • 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作

abstract修饰方法:抽象方法

  • 抽象方法只有方法的声明,没有方法体
  • 包含抽象方法的类一定是抽象类,反之,抽象类中可以没有抽象方法
  • 若子类重写了父类中所有的抽象方法后,此子类方可实例化
    若子类没有重写了父类中所有的抽象方法,则此子类也是一个抽象类,需要使用abstract 修饰
package com.atguigu.chapter6;

public class AbstractTest {
	public static void main(String[] args) {
		//一旦Person抽象了,就不可再实例化
		//Perosn p1 = new Person();
		
	}
}

abstract class Person{
	String name;
	int age;
	
	public Person() {
		
	}
	
	public Person(String name,int age) {
		this.name = name;
		this.age = age;
	}
	
	//抽象方法
	public abstract void eat();
	
	public void walk() {
		System.out.println("走路!");
	}
}

class Student extends Person{
	public Student(String name,int age) {
		super(name,age);
	}
	
	public void eat() {
		System.out.println("学生需要多干饭!");
	}
}

abstract 使用上的注意点

  • abstract 不能用来修饰:属性,构造器等结构
  • abstract 不能用来修饰私有方法,静态方法,final修饰的方法,final修饰的类

抽象类与抽象方法的课后练习

编写一个Employee类,声明为抽象类,包含如下三个属性:name,id,salary。提供必要的构造器和抽象方法:work()。
对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。
请使用继承的思想,设计CommonEmployee类和Manager类,要求类中提供必要的方法进行属性访问。

package com.atguigu.chapter6;

abstract public class Employee {
	private String name;
	private int id;
	private double salary;
	
	public Employee() {
		
	}
	
	public Employee(String name,int id,double salary) {
		this.name = name;
		this.id = id;
		this.salary = salary;
	}
	
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public double getSalary() {
		return salary;
	}

	public void setSalary(double salary) {
		this.salary = salary;
	}

	public abstract void work();
}

package com.atguigu.chapter6;

public class Manager extends Employee{
	
	private double bonus;
	
	public Manager() {
		
	}

	public Manager(String name, int id, double salary, double bonus) {
		super(name, id, salary);
		this.bonus = bonus;
	}

	
	public double getBonus() {
		return bonus;
	}

	public void setBonus(double bonus) {
		this.bonus = bonus;
	}

	@Override
	public void work() {
		System.out.println("Hr!");
	}
	
	
}

package com.atguigu.chapter6;

public class CommonEmployee extends Employee {


	@Override
	public void work() {
		System.out.println("打工人 打工魂!");

	}

}

抽象类的匿名子类

package com.atguigu.chapter6;

public class PersonTest {
	public static void main(String[] args) {
		method1(new Student());//匿名对象
		
		Worker worker = new Worker();
		method2(worker);//非匿名类  非匿名对象
		
		method2(new Worker());//非匿名类   匿名对象
		
		//创建了一匿名子类的对象 p
		Person1 p = new Person1() {

			@Override
			public void eat() {
				// TODO Auto-generated method stub
				
			}
			
		};
		
		method2(p);
		
		//创建匿名子类的匿名对象
		method2(new Person1() {

			@Override
			public void eat() {
				// TODO Auto-generated method stub
				
			}
			
		});
	
	}
	
	public static void method1(Student s) {
		
	}
	
	public static void method2(Person1 p) {
			p.eat();
			p.walk();
		}
}

class Worker extends Person1{
	/* (non-Javadoc)
	 * @see com.atguigu.chapter6.Person1#eat()
	 */
	@Override
	public void eat() {
		// TODO Auto-generated method stub
		
	}
}

模板方法设计模式(TemplateMethod)

抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。

解决的问题:

  • 当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
  • 换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式

模板方法测试举例

package com.atguigu.chapter6;

public class TemplateTest {
	public static void main(String[] args) {
		SubTemplate t1 = new SubTemplate();
		t1.speedTime();
	}
}

abstract class Template{
	
	//计算某段代码执行需要花费的时间
	public void speedTime() {
		
		long start = System.currentTimeMillis();
		
		code();// 不确定的部分
		
		long end = System.currentTimeMillis();
		
		System.out.println("花费的时间为" + (end - start));
	}
	
	public abstract void code();
}


class SubTemplate extends Template{

	/* (non-Javadoc)
	 * @see com.atguigu.chapter6.Template#code()
	 */
	@Override
	public void code() {
		
		for(int i = 2;i < 1000;i++) {
			boolean isFlag = true;
			
			for(int j = 2;j <= Math.sqrt(i);j++) {
				if(i % j == 0) {
					isFlag = false;
					break;
				}
			}
			
			if(isFlag) {
				System.out.println(i);
			}
		}
	}
	
}

模板方法设计模式是编程中经常用得到的模式。各个框架、类库中都有他的影子。

抽象类的课后练习题

编写工资系统,实现不同类型员工(多态)的按月发放工资。如果当月出现某个Employee对象的生日,则将该雇员的工资增加100元

  • 定义一个Employee类,该类包含:
    private成员变量name,number,birthday,其中birthday 为MyDate类的对象;
    abstract方法earnings();
    toString()方法输出对象的name,number和birthday。

  • MyDate类包含:
    private成员变量year,month,day ;
    toDateString()方法返回日期对应的字符串:xxxx年xx月xx日

  • 定义SalariedEmployee类继承Employee类,实现按月计算工资的员工处理。该类包括:
    private成员变量monthlySalary;
    实现父类的抽象方法earnings(),该方法返回monthlySalary值;
    toString()方法输出员工类型信息及员工的name,number,birthday。

  • 参照SalariedEmployee类定义HourlyEmployee类,实现按小时计算工资的员工处理。该类包括:
    private成员变量wage和hour;
    实现父类的抽象方法earnings(),该方法返回wage*hour值;
    toString()方法输出员工类型信息及员工的name,number,birthday。

  • 定义PayrollSystem类,创建Employee变量数组并初始化,该数组存放各类雇员对象的引用。
    利用循环结构遍历数组元素,输出各个对象的类型,name,number,birthday,以及该对象生日。
    当键盘输入本月月份值时,如果本月是某个Employee对象的生日,还要输出增加工资信息。

package com.atguigu.exer6;

public abstract class Employee {
	private String name;
	private int number;
	private MyDate birthday;
	
	
	public Employee(String name, int number, MyDate birthday) {
		super();
		this.name = name;
		this.number = number;
		this.birthday = birthday;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

	public MyDate getBirthday() {
		return birthday;
	}

	public void setBirthday(MyDate birthday) {
		this.birthday = birthday;
	}

	public abstract double earnings();

	@Override
	public String toString() {
		return " name=" + name + ", number=" + number + ", birthday=" + birthday.toDateString();
	}
		
}

package com.atguigu.exer6;

public class MyDate {
	private int year;
	private int month;
	private int day;
	
	
	
	public MyDate(int year, int month, int day) {
		super();
		this.year = year;
		this.month = month;
		this.day = day;
	}
	
	public int getYear() {
		return year;
	}
	
	public void setYear(int year) {
		this.year = year;
	}
	
	public int getMonth() {
		return month;
	}
	
	public void setMonth(int month) {
		this.month = month;
	}
	
	public int getDay() {
		return day;
	}
	
	public void setDay(int day) {
		this.day = day;
	}
	
	public String toDateString() {
		return year + "年" + month + "月" + day + "日";
	}
	
	
}

package com.atguigu.exer6;

public class SalariedEmployee extends Employee {
	private double monthlySalary;
	
	public SalariedEmployee(String name, int number, MyDate birthday) {
		super(name, number, birthday);
	}
	
	public SalariedEmployee(String name, int number, MyDate birthday,double monthlySalary) {
		super(name, number, birthday);
		this.monthlySalary = monthlySalary;
	}
	
	public double getMonthlySalary() {
		return monthlySalary;
	}

	public void setMonthlySalary(double monthlySalary) {
		this.monthlySalary = monthlySalary;
	}

	@Override
	public double earnings() {
		return monthlySalary;
	}

	@Override
	public String toString() {
		return "SalariedEmployee [" + super.toString() + "]";
	}
	
	
}

package com.atguigu.exer6;

public class HourlyEmployee extends Employee{

	private int wage;
	private int hour;
	
	public HourlyEmployee(String name, int number, MyDate birthday) {
		super(name, number, birthday);
	}
	
	public HourlyEmployee(String name, int number, MyDate birthday,int wage,int hour) {
		super(name, number, birthday);
		this.wage = wage;
		this.hour = hour;
	}
	
	public int getWage() {
		return wage;
	}

	public void setWage(int wage) {
		this.wage = wage;
	}

	public int getHour() {
		return hour;
	}

	public void setHour(int hour) {
		this.hour = hour;
	}

	@Override
	public double earnings() {
		return wage*hour;
	}

	public String toString() {
		return "HourlyEmployee [ " + super.toString() + "]";
	}
}

package com.atguigu.exer6;

import java.util.Scanner;

public class PayrollSystem {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		
		System.out.print("请输入本月月份:");
		int nowMonth = scan.nextInt();
		
		
		Employee[] emps = new Employee[2];
		emps[0] = new SalariedEmployee("花生", 1002, new MyDate(1992,2,28),10000);
		emps[1] = new HourlyEmployee("雨生", 2001, new MyDate(1991,5,10),60,240);
		
		for(int i = 0;i < emps.length;i++) {
			System.out.println(emps[i]);
			double salary = emps[i].earnings();
			System.out.println("月工资为:" + salary);
			
			
			if(emps[i].getBirthday().getMonth() == nowMonth) {
				System.out.println("生日快乐!奖励100元");
			}
		}
		
	}
}

接口(interface)

接口的使用

接口使用interface来定义

Java中,接口和类是并列的两个结构

如何定义接口:定义接口中的成员

  • JDK7及以前:只能定义全局常量和抽象方法
    全局常量:public static final xxx ,书写时,可以省略 public static final 关键字
    抽象方法:public abstract xxx
  • JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法,默认方法(回来补笔记)
    接口中定义的静态方法,只能通过接口来调用
    通过实现类的对象,可以调用接口中的默认方法
    如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
    如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的前提下,默认调用的是父类中同名同参数的方法(类优先原则)
    如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错。接口冲突
    解决方法:实现类必须覆盖接口中同名同参数的方法
    在子类(或实现类)中调用父类或者接口中被重写的方法~(看代码)

接口中不能定义构造器!意味着接口不可以实例化

Java开发中,接口通过让类去实现的方式(implements)来使用 (面向接口编程)

  • 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
  • 如果实现类没有覆盖了接口中的所有抽象方法,则此实现类仍为一个抽象类

Java类可以实现多个接口 : 弥补了Java单继承性的局限性
格式:class AA extends BB implements CC,DD,EE {}

接口与接口之间可以继承,而且可以多继承

接口的具体使用

  • 接口使用上也满足多态性
  • 接口,实际上就是定义了一种规范
  • 开发中,体会面向接口编程

接口,实际上可以看做是一种规范

package com.atguigu.chapter6;

public class InterfaceTest {
	public static void main(String[] args) {
		System.out.println(Flyable.MAX_SPEED);
		System.out.println(Flyable.MIN_SPEED);
		
		Plane p = new Plane();
		p.fly();
		p.stop();
	}
}

interface Flyable{
	//全局常量
	public static final int MAX_SPEED = 7900;
	int MIN_SPEED = 1;//省略  public static final
	
	//抽象方法
	public abstract void fly();
	
	void stop();//省略 public abstract 
	
}

interface Attackable{
	void attack();
}

class Plane implements Flyable{


	@Override
	public void fly() {
		System.out.println("通过引擎去飞!");
	}

	
	@Override
	public void stop() {
		System.out.println("驾驶员手动停止!");
		
	}
	
}

abstract class kite extends Plane{
	
}

class Bullet extends Object implements Flyable,Attackable,CC{

	@Override
	public void attack() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void method1() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void method2() {
		// TODO Auto-generated method stub
		
	}
	
}

//****************************
interface AA{
	void method1();
}
interface BB{
	void method2();
}
interface CC extends AA,BB{
	
}
package com.atguigu.chapter6;
//接口的使用
public class USBTest {
	public static void main(String[] args) {
		Computer com = new Computer();
		//1.创建了接口的非匿名实现类的非匿名对象
		Flash falsh = new Flash();
		com.transferData(falsh);
		
		//2.创建了接口的非匿名实现类的匿名对象
		com.transferData(new Printer());
		
		//3.创建了接口的匿名实现类的非匿名对象
		USB phone = new USB() {

			@Override
			public void start() {
				System.out.println("手机开始工作!");
			}

			@Override
			public void stop() {
				System.out.println("手机停止工作!");
			}
			
		};
		
		com.transferData(phone);
		
		//4.创建了接口的匿名实现类的匿名对象
		com.transferData(new USB() {
			@Override
			public void start() {
				System.out.println("mp3开始工作!");
			}

			@Override
			public void stop() {
				System.out.println("mp3停止工作!");
			}
		});
	}
}

class Computer{
	
	public void transferData(USB usb) {
		usb.start();
		
		System.out.println("具体的数据传输细节");
		
		usb.stop();
	}
}
interface USB{
	//定义长,宽,最大最小的传输速率
	void start();
	
	void stop();
}

class Flash implements USB{

	@Override
	public void start() {
		System.out.println("U盘开始工作!");
	}

	@Override
	public void stop() {
		System.out.println("U盘停止工作!");
	}
	
}

class Printer implements USB{

	@Override
	public void start() {
		System.out.println("打印机开始工作!");
	}

	@Override
	public void stop() {
		System.out.println("打印机停止工作!");
	}
	
}

面试题:抽象类 与 接口有哪些异同?
在这里插入图片描述
在开发中,常看到一个类不是去继承一个已经实现好的类,而是要么继承抽象类,要么实现接口。

接口的应用:代理模式(Proxy)

概述:代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。(暂时不深究)

package com.atguigu.chapter6;

public class NetWorkTest {
	public static void main(String[] args) {
		Server server  = new Server();
		ProxyServer proxyServer = new ProxyServer(server);
		proxyServer.browse();
		
	}
}

interface NetWork{
	public abstract void browse();
}
//被代理类
class Server implements NetWork{
	
	public  void browse() {
		System.out.println("真实的服务器访问网络!");
	}
}
//代理类
class ProxyServer implements NetWork{
	
	private NetWork work;
	
	public ProxyServer(NetWork work) {
		this.work = work;
	}
	
	public void check() {
		System.out.println("联网之前的检查工作!");
	}
	
	public void browse() {
		check();
		work.browse();
	}
}

应用场景:

  • 安全代理:屏蔽对真实角色的直接访问
  • 远程代理:通过代理类处理远程方法调用(RMI)
  • 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象

分类

  • 静态代理(静态定义代理类)
  • 动态代理(动态生成代理类)
    JDK自带的动态代理,需要反射等知识

接口课后练习题1

package com.atguigu.chapter6;
//排错
interface A {
	int x = 0;
}

class B {
	int x = 1;
}

class C extends B implements A {
	public void pX() {
		//System.out.println(x);//The field x is ambiguous
		System.out.println(super.x);//1
		System.out.println(A.x);//0
	}

	public static void main(String[] args) {
		new C().pX();
	}
}
package com.atguigu.chapter6;
//排错
interface Playable {
	void play();
}

interface Bounceable {
	void play();
}

interface Rollable extends Playable, Bounceable {
	Ball ball = new Ball("PingPang");
}

class Ball implements Rollable {
	private String name;

	public String getName() {
		return name;
	}

	public Ball(String name) {
		this.name = name;
	}

	public void play() {
		ball = new Ball("Football");// 全局常量 不可被修改 
		System.out.println(ball.getName());
	}
}

接口课后练习题2

  • 定义一个接口用来实现两个对象的比较。
	interface CompareObject{
	public int compareTo(Object o); //若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小
}
  • 定义一个Circle类,声明redius属性,提供getter和setter方法
  • 定义一个ComparableCircle类,继承Circle类并且实现CompareObject接口。在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小
  • 定义一个测试类InterfaceTest,创建两个ComparableCircle对象,调用compareTo方法比较两个类的半径大小
package com.atguigu.exer6;

public interface CompareObject {
	//若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小

	public int compareTo(Object o); 
}

package com.atguigu.exer6;

public class Circle {
	private double radius;
	
	public Circle() {
		
	}
	
	public Circle(double radius) {
		this.radius = radius;
	}
	
	public double getRadius() {
		return radius;
	}

	public void setRadius(double radius) {
		this.radius = radius;
	}
}

package com.atguigu.exer6;

public class ComparableCircle extends Circle implements CompareObject{

	public ComparableCircle(double radius) {
		super(radius);
	}
	@Override
	public int compareTo(Object o) {
		ComparableCircle cir = (ComparableCircle)o;
		if(this.getRadius() == cir.getRadius()) {
			return 0;
		}else if(this.getRadius() > cir.getRadius()) {
			return 1;
		}else {
			return -1;
		}
	}
}

package com.atguigu.exer6;

public class InterfaceTest {
	public static void main(String[] args) {
		ComparableCircle cir1 = new ComparableCircle(4.8);
		ComparableCircle cir2 = new ComparableCircle(5.4);
		
		int result = cir1.compareTo(cir2);
		System.out.println("结果是:" + result)	
	}
}

java8 中接口的新特性

package com.atguigu.chapter6;

public interface CompareA {
	
	//静态方法
	public static void method1() {
		System.out.println("CompareA:北京");
	}
	//默认方法
	public default void method2() {
		System.out.println("CompareA:上海");
	}
	default void method3() {// 省略 public
		System.out.println("CompareA:南京");
	}
	
}

package com.atguigu.chapter6;

public class SuperClass {
	public void method3() {
		System.out.println("SuperClass:南京");
	}
}

package com.atguigu.chapter6;

public interface CompareB {
	public default void method3() {
		System.out.println("CompareB:南京");
	}
}

package com.atguigu.chapter6;

public class SubClassTest {
	public static void main(String[] args) {
		
		SubClass s = new SubClass();
		//s.method1();//The method method1() is undefined for the type SubClass
		CompareA.method1();
		
		s.method2();
		s.method3();
		
	}
	
}

class SubClass extends SuperClass implements CompareA,CompareB{
	public  void method2() {
		System.out.println("SubClass:上海");
	}
	
	public  void method3() {
		System.out.println("SubClass:南京");
	}
	
	public void myMethod() {
		method3();//调用子类重写的方法
		super.method3();//调用父类的方法 
		//调用接口中的默认方法
		CompareA.super.method3();
		CompareB.super.method3();
	}
}

类的内部成员之五:内部类

内部类的使用

Java中允许将一个类A声明在另一个类B的内部,则类A就是内部类,类B就是外部类

内部类的分类:成员内部类(静态,非静态) vs 局部内部类(方法内,代码块内,构造器内)

成员内部类

  • 一方面,作为外部类的成员
    调用外部类的结构
    可以被static修饰
    可以被4种权限修饰
  • 另一方面,作为一个类:
    类内可以定义属性,方法,构造器等
    可以被final修饰,表示此类不能被继承
    可以被abstract修饰,表示此类不能实例化

关注如下的3个问题

  • 如何实例化成员内部类的对象
  • 如何在成员内部类中区分调用外部类的结构
  • 开发中局部内部类的使用
package com.atguigu.chapter6;

public class InnerClassTest {
	public static void main(String[] args) {
		//创建Dog实例(静态的成员内部类)
		Person2.Dog dog = new Person2.Dog();
		dog.show();
		
		//创建Bird实例(非静态的成员内部类)
		//Person2.Bird bird = new Person2.bird();错误
		Person2 p = new Person2();
		Person2.Bird bird  = p.new Bird();
		bird.sing();
		bird.display("伍六一");
	}
}

class Person2{
	
	String name = "九十九";
	int age;
	
	public void eat() {
		System.out.println("恰饭,恰饱饱");
	}
	
	//静态 成员内部类
	static class Dog{
		String name;
		
		public void show() {
			System.out.println("中华田园犬!");
		}
	}
	//非静态 成员内部类
	class Bird{
		String name = "黄鹂";
		
		
		public void sing() {
			System.out.println("我是一只小小鸟!");
			Person2.this.eat();//调用外部类的非静态属性
		}
		
		public void display(String name) {
			System.out.println(name);//方法的形参
			System.out.println(this.name);//内部类的属性
			System.out.println(Person2.this.name);//外部类的属性
		}
	}
	//局部内部类
	public Person2() {
		class BB{
			
		}
	}
	
	{
		class CC{
			
		}
	}
	
	public void method() {
		class AA{
			
		}
	}
}
package com.atguigu.chapter6;

public class InnerClassTest2 {
	
	//开发中很少见
	public void method() {
		//局部内部类
		class AA{
			
		}
	}
	
	//返回一个实现Comparable接口的类的对象:
	public Comparable getComparable() {
		
		//创建了一个实现Comparable接口的类//局部内部类
		//方式一:
//		class MyComparable implements Comparable{
//
//			@Override
//			public int compareTo(Object o) {
//				return 0;
//			}
//			
//		}
//		
//		return new MyComparable();
		
		//方式二
		return new Comparable() {

			@Override
			public int compareTo(Object o) {
				return 0;
			}
			
		};
	}
}

参考资料

尚硅谷-Java零基础教程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值