08面向对象(高级)类变量和方法、代码块、单例设计模式、final、抽象类(abstract)、接口、内部类

类变量和类方法

static:

static变量是对象共享
static类变量,在类加载的时候就生成了

什么是类变量:

类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,渠道的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。

如何定义类变量

定义语法:

访问修饰符 static 数据类型 变量名;
static 访问修饰符 数据类型 变量名;

如何访问类变量:

类名.类变量名。或者 对象名.类变量名[静态变量的访问修饰符的访问权限和范围和普通属性是一样的]

类变量使用注意事项和细节:

1什么时候需要用类变量:
当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量)。如:定义一个学生类,统计所有学生交多少钱。
2类变量与实例变量(普通属性)区别:
类变量是该类的所有对象共享的,而实例变量时每个对象独享的。
3加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量
4类变量可以通过 类名.类变量名 或者 对象名.类变量名 来访问。[前提是满足访问修饰符的访问权限和范围]
5实例变量不能通过 类名.类变量名 方式访问
6类变量是在类加载时就初始化了,即使没有创建对象,只要类加载了,就可以使用类变量了。
7类变量的声明周期是随类的加载开始,随着类消亡而销毁。

类方法基本介绍:

类方法也叫静态方法。
访问修饰符 static 数据返回类型 方法名(){}
static 访问修饰符 数据返回类型 方法名(){}

类方法的调用:

使用方式:类名.类方法名 或者 对象名.类方法名

类方法经典使用场景:

当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率。
在实际开发,往往会将一些通用的方法设计成静态方法,这样我们不需要创建对象就可以使用。比如打印一维数组,冒泡排序,完成某个计算机任务等等

类方法使用注意事项和细节:

1类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:
	类方法中无this的参数
	普通方法中隐含着this的参数
2类方法可以通过类名调用,也可以通过对象名调用
3普通方法和对象有关,需要通过对象名调用,比如对象名.方法名(参数),不能通过类名调用
4类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以。
5类方法(静态方法)中只能访问静态变量或静态方法。
6普通成员方法,既可以访问普通变量(方法),也可以访问静态变量。
小结:静态方法,只能访问静态的成员,非静态的方法,可以访问静态成员和非静态成员

练习:

1下面输出内容是什么
public class Test{
	static int count = 9;
	public void count(){
		System.out.println("count="+count++);
	}
	public static void main(String[] args){
		new Test().count();//9
		new Test().count();//10
		System.out.println(Test.count);//11
	}
}
2看看下面代码有没有错误,如果有就修改,最后输出内容是什么
class Person{
	private int id
	private static int total = 0;
	public static int getTotalPerson(){
		//id++;//错误 静态方法不能调用非静态成员
		return total;//0
	}
	public Person(){//构造器
		total++;
		id = total;
	}
}
public class TestPerson{
	public static void main(String[] args){
		System.out.println(Person.getTotalPerson());//0
		Person p1 = new Person();
		System.out.println(Person.getTotalPerson());//1
	}
}
3看看下面代码有没有错误,如果有就修改,最后输出内容是什么
class Person{
	private int id
	private static int total = 0;
	public static int setTotalPerson(int total){
		//this.total = total;//静态方法不能使用this
		Person.total = total;//0
	}
	public Person(){//构造器
		total++;//1
		id = total;//1
	}
}
public class TestPerson{
	public static void main(String[] args){
		Person.setTotalPerson(3);//3
		new Person();//4class Person{
	private int id
	private static int total = 0;
	public static int getTotalPerson(){
		//id++;//错误 静态方法不能调用非静态成员
		return total;//0
	}
	public Person(){//构造器
		total++;
		id = total;
	}
}
public class TestPerson{
	public static void main(String[] args){
		System.out.println(Person.getTotalPerson());//0
		Person p1 = new Person();
		System.out.println(Person.getTotalPerson());//1
	}
}
	}
}

main:

深入理解mian方法:

解释main方法的形式:public static void main(String[] args){}
	1.main方法是虚拟机调用
	2.java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public
	3.java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static
	4.该方法接受String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数。
	5.java执行的程序 参数1 参数2 参数3

特别提示:

1在main()方法中,我们可以直接调用main方法所在类的静态方法和静态属性。但是不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员。

代码块

基本介绍:

代码化块又称为初始化块,属于类中的成员[是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过{}包围起来
但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显示调用,而是加载类时,或创建对象时隐式调用

基本语法:

[修饰符]{
	代码
};
注意:
1.修饰符 可选,要写的话,也只能写static
2.代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块.
3.逻辑与局可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)
4.;号可以写上,也可以省略。

使用注意事项和细节:

1.static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象,就执行
2.类什么时候被加载:
	1创建对象实例时(new)
	2创建子类对象实例,父累也会被加载
	3实用类的静态成员时(静态属性,静态方法)
3.普通的代码块,在创建对象实例时,会被隐式的调用。被创建一次,就会调用一次。如果只是实用类的静态成员时,普通代码块并不会执行。
4.创建一个对象时,在一个类调用顺序是:
	1调用静态代码块和静态属性初始化(静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
	2调用普通代码块和普通属性的初始化(普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
	3调用构造方法
5.构造器的最前面其实隐含了super()和调用普通代码块。静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于 构造器和普通代码块执行的
6.创建一个子类时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
	1父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
	2子类的静态代码块和静态属性
	3父类的普通代码块和普通属性初始化
	4父类的构造方法
	5子类的普通代码块和普通属性初始化
	6子类的构造方法
7.静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员

练习:

1下面代码输出什么:
class Person{
	public static int total;
	static{
	total = 100;
	System.out.println("in static block");
	}
}
public class Test{
	public static void main(String[] args){
		System.out.println("total="+person.total);//in static,100
		System.out.println("total="+person.total);//100
	}
}
2下面代码输出什么:
class Sample{
	Sample(String s){System.out.println(s);}
	Sample(){System.out.println("Sample 默认构造函数");}
}
class Test{
	Sample sam1 = new Sample("sam1 成员初始化");//3
	static Sample sam = new Sample("静态成员sam初始化");//1
	static{
		System.out.println("static块执行");//2
		if(Sam==null){System.out.println("sam is null);"}
	}
	Test(){System.out.println("Test 默认构造函数");}//4
}
//主方法
public static void main(String[] args){
	Test a = new Test();//无参构造器
}
输出为:静态成员sam初始化,static块执行,sam1 成员初始化,Test 默认构造函数

单例设计模式

什么是设计模式

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

什么是单例模式

1.所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类智能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
2.单例模式有两种方式:1饿汉模式 2懒汉式

饿汉式VS懒汉式

1.而这最主要的区别就在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。
2.饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
3.饿汉式存在浪费资源的可能。因为如果一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。
4.在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式

小结:

1.单例模式的两种实现方式:一、饿汉式		二、懒汉式
2.饿汉式的问题:在类加载的时候就创建,可能存在资源浪费问题
3.懒汉式的问题:线程安全问题,

final关键字

final基本介绍:

final 中文意思:最后的,最终的
final 可以修饰类、属性,方法和局部变量
在某些情况下,可能有以下需求,就会使用到finl:
	1.当不希望类被继承时,可以用final修饰
	2.当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰
	3.当不希望类的某个属性的值被修改,可以用final修饰
	4.当不希望某个局部变量被修改,可以使用final修饰

final注意事项和细节:

1.final修饰的属性又叫常量,一般用xx_xx来命名
2.final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一:
	1定义时:如public final double TEX_RATE = 0.1;
	2在构造器中
	3在代码块中
3.如果final修饰的属性是静态的,则初始化的位置只能是
	1定义时		2静态代码块,不能再构造器中赋值
4.final类不能被继承,但可以实例化对象
5.如果类不是final类,但含有final方法,则该方法虽然不能重写,但是可以被继承
6.一般来说,如果一个类已经final类了,就没有必要在方法修饰成final方法
7.final不能修饰构造方法(构造器)
8.final和static往往搭配使用,效率更高,不会导致类加载。底层编译器做了优化处理
9.包装类(Integer,Double,Float,Boolean等都是final),String也是final类

final实例:

请编写一个程序,能计算圆形的面积。要求圆周率为3.14赋值的位置3个方式都写一遍
public class FinalExercise01 {
	public static void main(String[] args) {
		Circle circle = new Circle(5);
		System.out.println(circle.calArea());
	}
}
class Circle {
	private double radius;
	private final double PI = 3.14;
	public Circle(double radius) {
		this.radius = radius;
		//PI=3.14
	}
	{// PI = 3.14;}
	public double calArea(){return PI * radius *radius;}
}
2程序阅读
public class Something{
	public int addOne(final int x){++x; return x+1;}
}
//++X错,不能修改final x的值

抽象类

抽象类快速入门:

当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法,用abstract来修饰该类就是抽象类。

抽象类的介绍:

1.用abstract关键字来修饰一个类时,这个类就叫抽象类
	访问修饰符 abstract 类名{}
2.用abstract关键字来修饰一个方法时,这个方法就是抽象方法。
	访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
3.抽象类的价值更多作用是在于设计,在设计者设计好后,让子类继承并实现抽象类()。
4.抽象类,在框架和设计模式使用较多

抽象类使用的注意事项和细节

1.抽象类不能被实例化
2.抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法。
3.一旦类包含了abstract方法,则这个类必须声明abstract。
4.abstract只能修饰类和方法,不能修饰属性和其它。
5.抽象类可以有任意成员。如:非抽象方法、构造器、静态属性等待
6.抽象方法不能有主体,既不能实现
7.如果一个类继承了抽象类,则它必须抽象类的所有抽象方法,除非它自己也声明为abstract类。
8.抽象方法不能使用private、final和static来修饰,因为这些关键字都是和重写相违背的。

练习题:

1.思考:abstract final class A{}能编译通过吗。
	不可以,因为final不能被继承,abstract需要被继承   
2.思考:abstract public static void test2();能编译通过吗。
	不可以,因为static关键字和方法重写无关
3.思考:abstract private void test3;能编译通过吗
	不可以,因为private是私有的
4.编写一个Employee类,声明为抽象类,包含如下三个属性:name,id,salary.提供必要的构造器和抽象方法:work()。对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。请使用继承的思想,设计CommonEmployee类和Manager类,要求类中提供必要的方法进行属性访问,实现work(),提示"经理/普通员工  名字  工作中..."

抽象类实践-模板设计模式

要求:1有多个类,完成不同的任务code()	2要求能够得到各自完成任务的实践
public abstract class Template {
	public abstract void code();//抽象方法
	public void calcTime(){//实现方法,调用code
		//开始时间
		long start = System.currentTimeMillis();
		code();
		//结束时间
		long end = System.currentTimeMillis();
		System.out.println("AA执行时间" + (end - start));
	}
}
class Sub extends Template{
	@Override
	public void code() {
		long num = 0;
		for (long i = 1; i <= 1000000; i++) {
			num = ++i;
		}
	}
}

接口:

基本介绍:

借口就是给出一些没有实现的方法,封装到一起,到某个类要是用的时候,再根据具体情况把这些方法写出来。语法:
interface 接口名{
	//属性
	//方法(1抽象方法	2默认实现方法[default]	3静态方法)
}
class 类名 implements 接口{
	自己属性;
	自己方法;
	必须事先的接口的抽象方法
}

小结:

1.在JDK7.0前 接口里的所有方法都没有方法体,都是抽象方法。
2.JDK8.0后接口类可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现

接口注意事项和细节

1.接口不能被实例化
2.接口中所有的方法时public方法,接口中抽象方法,可以不用abstract修饰
3.一个普通类实现接口,就必须将该接口的所有方法都实现
4.抽象类实现接口,可以不用实现接口的方法
5.一个类同时可以实现多个接口
6.接口中的属性,只能是final的,而且是public static final 修饰符。比如:
	int a=1;实际上是public static fianl int a=1;(必须初始化)
7.接口中属性的访问形式:接口名.属性名
8.一个接口不能继承其它的类,但是可以继承多个别的接口
	interface A extends B,c{}
9.接口的修饰符 只能是public和默认,这点和类的修饰符是一样的

实现接口VS继承:

1接口和继承解决的问题不同:
	继承的价值主要在于:解决代码的复用性和维护性
	接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法。
2接口比继承更加灵活:
	接口比继承更加灵活,继承时满足is-a的关系,而接口只需要满足like-a的关系。
3接口在一定程度上实现代码解耦

接口的多态性:

1.多态参数:USB接口即可以接收手机对象,又可以接收相机对象,就体现了接口多态(接口引用可以指向实现了接口的类的对象)
2.多态数组:给USB数组中,存放手机和相机对象,手机类还有一个特有的方法callPhone特有方法call。
3.接口存在多台传递现象。

练习:

1、interface A{
	int a=23;
}
class B implements A{}
public static void main(String[] args){
	B b=new B();
	System.out.println(b.a);//23
	System.out.println(A.a);//23
	System.out.println(B.a);//23
}
2、interface A{ int x=0; }//等价于public static final int x=0;
class B{ int x = 1; }
class C extends B implements A{
	
	public void pX(){
	/*	System.out.println(x);//错误
		可以明确的指定x
		访问接口的 x 就使用 A.x
		访问父类的 x 就使用 super.x
	*/
		System.out.println(A.x+" "+super.x);
	}
	public static void main(String[] args){
		new C().pX(); //0,1
	}
}

类定义的进一步完善:

内部类

内部类基本介绍:

一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class),是我们类的第五大成员[属性、方法、构造器、代码块、内部类]。内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类直接的包含关系。(注意:内部类是学习的难点,同时也是重点,后面看底层源码时,有大量的内部类。)

内部类基本语法:

class Outer{//外部类
	class inner{//内部类
	}
}
class Other{//外部其他类}

内部类的分类:

定义在外部类局部位置上:
	1局部内部类(有类名)
	2匿名内部类(没有类名)
定义在外部类的成员位置上:
	1成员内部类(没用static修饰)
	2静态内部类(使用static修饰)

局部内部类的使用:

说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名
1.可以直接访问外部类的所有成员,包括私有
2.不能添加访问修饰符,因为它的低位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final
3.作用域:仅在定义它的方法或代码块中
4.局部内部类-访问→外部成员[访问方式:直接访问]
5.外部类-访问→局部内部类的成员[访问方式:创建对象,在访问(必须在作用域内)]
记住:
	(1)局部内部类定义在方法中/代码块
	(2)作用域在方法体或者代码块中
	(3)本质仍然是一个类
6.外部其他类-不能访问→局部内部类(局部内部类是定义一个局部变量)
7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

匿名内部类的使用:

(1)本质是类(2)内部类(3)该类没有名字(4)同时还是一个对象
说明:匿名内部类就是定义在外部类的局部位置,比如方法中,并且没有类名
1.匿名内部类的基本语法
	new 类或接口 (参数列表){
		类体
	};
2.匿名内部类的语法比较奇特,匿名内部类即是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法
3.可以直接访问外部类的所有成员,包含私有的
4.不能添加访问修饰符,因为它的地位就是一个局部变量
5.作用域:仅仅在定义它的方法或代码块中
6.匿名内部类-访问→外部类成员
7.外部其它类-不能访问→匿名内部类(匿名内部类地位是一个局部变量)
8.如果外部类和内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

练习:

1.当作实参直接传递,简介高效。
public class InnerClassExercise01 {
	public static void main(String[] args) {
		//当作实参直接传递,简洁高效
		f1(new IL(){
			@Override
			public void show() {
				System.out.println("这是一幅画");
			}
		});
		//传统方式
		f1(new Picture());
	}
	//静态方法,形参是接口类型
	public static void f1(IL il){
		il.show();
	}
}
//接口
interface IL{
	void show();
}
//类→实现IL → 编程领域(硬编码)
class Picture implements IL{
	@Override
	public void show() {
		System.out.println("这是一幅画。。。");
	}
}
2.1有一个铃声接口Bell,里面有个ring方法。
	2有一个手机类Cellphone,具有闹钟功能alarmclock,参数是Bell类型
	3测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
	4.在传入另一个匿名内部类(对象),打印:小伙伴上课了
public class InnerClassExercise02 {
	public static void main(String[] args) {
		/*  1.传递的是实现了 Bell接口的匿名内部类 InnerClassExercise02$1
			2.重写了 ring
			3.Bell bell = new Bell();
		*/
		Cellphone cellphone = new Cellphone();
		cellphone.alarmclock(new Bell() {
			@Override
			public void ring() {
				System.out.println("懒猪起床了");
			}
		});
		cellphone.alarmclock(new Bell() {
			@Override
			public void ring() {
				System.out.println("小伙伴上课了");
			}
		});
	}
}
interface Bell{//接口
	void ring();//方法
}
class Cellphone{//类
	public void alarmclock(Bell bell){//形参是Bell接口类型
		bell.ring();
	}
}

成员内部类的使用:

说明:成员内部类是定义在外部类的成员位置,并且没有static修饰。
1.可以直接访问外部类的所有成员,包含私有的
2.可以添加任意访问修饰符(public、protected、默认、private),因为它的低位就是一个成员。
3.作用域和外部类的其它成员一样,为整个类体。在外部类的成员方法中创建成员内部类对象,在调用方法
4.成员内部类-访问→外部类成员(如:属性)[访问方式:直接访问]
5.外部类-访问→成员内部类(说明)[访问方式: 创建对象,在访问]
6.外部其它类-访问→成员内部类
第一种方式:outer08.new Innter08();相当于把new Inner08()当做是outer08成员
Outer08.Innter08 innter08 = outer08.new Innter08();
第二种方式:在外部类中,编写一个方法,可以返回Innter08方法
Outer08.Innter08 inner08Instance = outer08.getInner08Instance();
第三种方式
Innter08 innter081 = new Outer08().new Innter08();
7.如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

静态内部类的使用:

说明:静态内部类是定义在外部类的成员位置,并且有static修饰
1.可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
2.可以添加任意访问修饰符(public、protected、默认、private),因为它的低位就是一个成员。
3.作用域:同其他的成员,为整个类体
4.静态内部类-访问→外部类(如:静态属性)[访问方式:直接访问索引静态成员]
5.外部类-访问→静态内部类	访问方式:创建对象,在访问
6.外部其它类-访问→静态内部类
7.如果外部类和静态内部类的成员重名时,静态内部类访问时,默认转训就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)访问
小结:
	(1)内部类有四种 局部内部类,匿名内部类,成员内部类,静态内部类
	(2)重点还是掌握 匿名内部类使用 new 类/接口(参数列表){//...};
	(3)成员内部类,静态内部类 是放在外部类的成员位置,本质就是一个成员

练习:

(1)public class Test{//外部类
	public Test(){//构造器
		Inner s1 = new Inner();
		s1.a = 10;
		Inner s2 = new Inner();
		System.out.println(s2.a);
	}
	class Inner{//内部类
		public int a = 5;
	}
	public static void main(String[] args){//main方法
		Test t = new Test();//5
		Inner r = t.new Inner();
		System.out.println(r.a);//5
	}
}

作业:

1.试写出以下代码的执行结果()
	class Car{
		double price = 10;
		static String color = "white";
		public String toString(){
			return price+" "+color;
		}
		public Car(){
			this.price = 9;
			this.color = "red";
		}
		public Car(double price){
			this.price = price;}
	}
	public static void main(String[] args){
		Car c = new Car();
		Car c1 = new Car(100);
		System.out.println(c);//9,red
		System.out.println(c1);//100,red
	}
2编程题(静态属性和方法):
	1.在Frock类中声明私有的静态属性currentNum[int类型],初始值为1000,作为衣服出厂的序列号起始值
	2.声明公有的静态方法getNextNum,作为生成上衣唯一序列号的方法。没吊用一次,将currentNum增加100,并作为返回值
	3.在TestFrock类的main方法中,分两次调用getNextNum方法,获取序列号并打印输出。
	4.在Frock类中声明serialNumber(序列号)属性,并提供对应的get方法
	5.在Frock类的构造器中,通过调用getNextNum方法为Frock对象获取唯一序列号,赋给serialNumber属性。
	6.在TestFrock类的main方法中,分别创建三个Frock对象,并打印三个对象的序列号,验证是否为按100递增
点击查看代码
class Frock{
    private static int currentNum = 1000;//唯一序列号
    private int serialNumber;//序列号

    public Frock() {
        serialNumber = getNextNum();//通过构造器调用getNextNum()赋值给serialNumber
    }

    public static int getCurrentNum() {
        return currentNum;
    }

    public static int getNextNum() {
        currentNum += 100;//将currentNum增加100
        return currentNum;
    }

    @Override
    public String toString() {
        return serialNumber+" ";
    }
}

class TestFrock{
    public static void main(String[] args) {
        Frock frock = new Frock();
        System.out.println(frock);
        Frock frock1 = new Frock();
        System.out.println(frock1);
        Frock frock2 = new Frock();
        System.out.println(frock2);
    }
}
3编程题(抽象方法):
	1.动物类Animal包含了抽象方法shout();
	2.Cat类继承了Animal,并实现方法shout,打印"小猫会喵喵喵"
	3.Dog类继承了Animal,并实现方法shout,打印"小狗会汪汪汪"
	4.在测试类中实例化对象Animal cat = new Cat(),并调用cat的shout方法
	5.在测试类中实例化对象Animal dog = new Dog(),并调用dog的shout方法
点击查看代码
public class Exercise03 {

    public static void main(String[] args) {
        Animal cat = new Cat();
        Animal dog = new Dog();
        cat.shout();
        dog.shout();
    }
}

abstract class Animal{
    public abstract void  shout();
}

class Cat extends Animal{

    @Override
    public void shout() {
        System.out.println("小猫会喵喵喵");
    }
}

class Dog extends Animal{

    @Override
    public void shout() {
        System.out.println("小狗会汪汪汪");
    }
}
4编程题(匿名内部类):
	1.计算器接口具有work方法,功能是运算,有一个手机类Cellphone,定义方法testWork测试计算功能,调用计算接口的work方法
	2.要求调用CellPhone对象 的testWork方法,使用上 匿名内部类
点击查看代码
public class Exercise04 {

    public static void main(String[] args) {
        Cellphone cellphone = new Cellphone();
        cellphone.testWork(new Calculator() {
            @Override
            public double work(double d1, double d2) {
                return d1-d2;
            }
        },20,10);
    }
}

interface Calculator{
    //work方法 完成计算运算
    public double work(double d1,double d2);
}

class Cellphone{
    //当我们调用testWork方法时,直接传入一个实现了Calculator接口的匿名内部类即可
    //该匿名内部类,可灵活的实现work,完成不同的计算任务
    public void testWork(Calculator calculator,double d1, double d2){
        double result = calculator.work(d1,d2);
        System.out.println("计算结果为:"+result);
    }
}
5编程题(局部内部类):
	1.编译一个类A,在类中定义局部内部类B,B中有一个私有常量name,有一个方法show()打印常量name
	2.进阶:A中也定义一个私有的变量name,在show方法中打印
点击查看代码
public class Exercise05 {
    public static void main(String[] args) {
        A a = new A();
        a.fi();
    }
}

class A{//外部类
    private String name = "小白";
    public void fi(){
        class B{//内部类
            private String name = "小黑";
            public void show(){
                //如果内部类和外部类的属性重名,可以同过 外部类.this.属性名来指定
                System.out.println(name+" 外部类name="+A.this.name);
            }
        }
        B b = new B();
        b.show();
    }
}
6编程题():
	1.有一个交通工具接口类Vehicles,有work接口
	2.有Horse类和Boat类分别实现Vehicles
	3.创建交通工具工厂类,有两个方法分别获得交通工具Horse和Boat
	4.有Person类,有name和Vehicles属性,在构造器中为两个属性赋值
	5.实例化Person对象"唐僧",要求一般情况下用Horse作为交通工具,遇到大河时用Boat作为交通工具
	6.如果唐僧过火焰山,使用飞机(Aircraft)→程序扩展性
点击查看代码
interface Vehicles{
    public void work();
}

class Horse implements Vehicles {

    @Override
    public void work() {
        System.out.println("一般情况骑马");
    }
}

class Boat implements Vehicles {

    @Override
    public void work() {
        System.out.println("过河坐船");
    }
}

class Aircraft implements Vehicles{

    @Override
    public void work() {
        System.out.println("过火焰山坐飞机");
    }
}


class VehicleFactory {
    private static Horse horse = new Horse();//饿汉式
    //创建交通工具工厂类,有两个方法分别获得交通工具Horse和Boat
    //这里将方法做成静态方法 比较方便
    public static Horse getHorse() {
        return horse;
    }

    public static Boat getBoat() {
        return new Boat();
    }

    public static Aircraft getAircraft(){
        return new Aircraft();
    }
}
class Person{
    private String name;
    private Vehicles vehicles;
    //在创建人对象时,事先给他分配交通工具
    public Person(String name, Vehicles vehicles) {
        this.name = name;
        this.vehicles = vehicles;
    }


    /*
        实例化Person对象"唐僧",要求一般情况下用Horse作为交通工具,遇到大河时用Boat作为交通工具
        编程思路:可以把具体的要求,封装成方法→这就是编程思想

     */
    public void road(){
        //得到马
        //判断当前的 vehicles 属性是否已经存在
        /*
            vehicles instanceof Boat 判断当前的 vehicles 是不是Boat
            1 vehicles = null :vehicles instanceof Boat →false
            2 vehicles = 马对象 :vehicles instanceof Boat →false
            3 vehicles = 船对象 :vehicles instanceof Boat →true
         */
        if (!(vehicles instanceof Horse)){
            //使用多态向上转型
            vehicles = VehicleFactory.getHorse();
        }
        //体现接口调用
        vehicles.work();
    }
    public void sea(){
        //得到船
        if(!(vehicles instanceof Boat) ){
            vehicles = VehicleFactory.getBoat();
        }
        vehicles.work();
    }

    public void flameMountain(){
        //得到飞机
        if(!(vehicles instanceof  Aircraft)){
            vehicles = VehicleFactory.getAircraft();
        }
        vehicles.work();
    }
}
7编程题(内部类):
有一个Car类,有属性temperature(温度),车内有Air(空调)类,有吹风的功能flow,Air会监视车内的温度,如果温度超过40度则吹冷气.如果温度低于0度则吹暖气,如果在这之间则关掉空调.实例化具有不同温度的Car对象,调用空调的flow方法,测试空调吹的风是否正确.//体现 类与类的包含关系的案例  类(内部类[成员内部类])
点击查看代码
class Car{//外部类
    private double temperature;//温度

    public Car(double temperature) {
        this.temperature = temperature;
        Air air = new Air();
        air.flow();
    }
        class Air{
            public void flow(){
                if(temperature>40){
                    System.out.println("吹冷气");
                }else if(temperature<0){
                    System.out.println("吹暖气");
                }else{
                    System.out.println("关闭空调");
                }
            }
    }
}
posted @ 2022-03-07 22:09  栗子一块两块  阅读(27)  评论(0)    收藏  举报