类变量和类方法
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("关闭空调");
}
}
}
}