面向对象(三)
1:抽象类
(1)概念:包含抽象方法的类。
(2)理解:如果一个类中包含了一个或多个抽象方法,那么这个类就必须指定为abstract(抽象)。抽象方法属于一种不完整的方法,只有方法声明,没有方法主体。
例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。
(3)特点:
A:抽象类和抽象方法必须使用abstract修饰。
B:抽象类不能被实例化。
C:抽象类有抽象方法,用于子类实例化使用。
D:如果一个类是抽象类,那么继承它的子类
要么是抽象类,
要么重写所有抽象方法。
(4)抽象类的成员特点
A:成员变量: 可以是变量,也可以是常量。
B:构造方法: 有构造方法。
C:成员变量:可以是抽象方法,也可以是非抽象方法。
(5)抽象类相关的几个小问题
A:抽象类不能被实例化,为什么有构造?
用于子类实例化使用。
B:一个类没有抽象方法,为什么定义为抽象类?
不想被实例化。
C:abstract不能和那些关键字共存?
final
private
static
(6)案例
A:老师:
基础班老师
姓名,年龄
讲课:JavaSE
就业班老师
姓名,年龄
讲课:JavaEE
由于讲课内容不一样,但是都有讲课的功能。
所以,我们把讲课抽取出来。定义一个Teacher类。
接着来一个基础班Teacher继承,来一个就业班Teacher继承即可。
abstract class Teacher
{
private String name;
private int age;
public Teacher(){}
public Teacher(String name,int age)
{
this.name = name;
this.age = age;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setAge(int age)
{
this.age = age;
}
public int getAge()
{
return age;
}
public void show()
{
System.out.println(name+"****"+age);
}
public abstract void teach();
}
class BaseTeacher extends Teacher
{
public BaseTeacher(){}
public BaseTeacher(String name,int age)
{
super(name,age)
}
public void teach()
{
System.out.println("基础班老师讲解javaSE");
}
}
class WorkTeacher extends Teacher
{
public WorkTeacher(){}
public BaseTeacher(String name,int age)
{
super(name,age)
}
public void teach()
{
System.out.println(就业班老师讲解javaEE");
}
}
class AbstractTest
{
public static void main(String[] args)
{
//多态
//基础班老师
//无参构造
Teacher t = new BaseTeacher();
t.setName("林青霞");
t.setAge(26);
t.teach();
//t.show();
//带参构造
t = new BaseTeacher("李小璐",18);
t.teach();
t.show();
//就业班老师
t = new WorkTeacher("刘亦菲",30);
t.teach();
t.show();
t = new WorkTeacher();
t.setName("胡歌");
t.setAge(20);
t.teach();
t.show();
}
}
B:请用抽象类体现如下代码:
需求:公司中程序员有姓名,工号,薪水,工作内容。
项目经理除了有姓名,工号,薪水,还有奖金,工作内容。
abstract class Employee
{
private String name;
private int id;
private double pay;
public Employee(){}
Employee(String name,int id,double pay)
{
this.name=name;
this.id=id;
this.pay=pay;
}
public void setName(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
public void setId(int id)
{
this.id=id;
}
public int getId()
{
return id;
}
public void setPay(double pay)
{
this.pay=pay;
}
public double getPay()
{
return pay;
}
public void show()
{
System.out.println(name+"***"+id+"***"+ pay);
}
public abstract void work();
}
class Programmer extends Employee
{
public Programmer(){}
Programmer(String name,int id,double pay)
{
super(name,id,pay);
}
public void work()
{
System.out.println("programmer work");
}
}
class Manager extends Employee
{
public Manager(){}
private int bonus;
Manager(String name,int id,double pay ,int bonus)
{
super(name,id,pay);
this.bonus=bonus;
}
public void setBonus(int bonus)
{
this.bonus=bonus;
}
public int getBonus()
{
return bonus;
}
public void work()
{
System.out.println("manager work"+"奖金:"+bonus);
}
}
class EmployeeDemo
{
public static void main(String[] args)
{
//程序员
Employee e=new Programmer();
e.work();
e.setName("林志颖");
e.setId(01);
e.setPay(4000);
e.show();
//经理
e=new Manager("刘亦菲",005,10000,2000);
e.work();
e.show();
}
}
2.接口
(1)概念:如果一个抽象类中的方法都是抽象的,这时java就提供了一种更加抽象的表现形式—接口。
接口:interface
实现:implements
格式:
interface 接口名{}
class 类名 implements 接口名{}
(2)接口的特点
A:接口不能被实例化。
B:一个如果实现了接口,
要么,实现接口中的所有方法
要么,是一个抽象类。
(3)接口的成员特点
A:成员变量:只能是常量,默认修饰符为 public static final。
B:成员方法:只能是抽象,默认修饰符为 public abstract。
(4)接口的思想特点
A:对外暴露规则。
B:是对功能的扩展。
C:降低耦合性
耦合:是指类与类的关系。
内聚:是之类自己完成某件事情的能力。
D:接口可以多实现。
(5)类,接口的关系
A:类与类的关系
继承关系,只能单继承,不能多继承,可以多重继承。
B:类与接口的关系
实现关系,可以单实现,也可以多实现。
C:接口与接口的关系
继承关系,可以单继承,也可以多继承。
D:抽象类与接口的关系
接口是一种特殊的抽象类,比抽象类更抽
因为接口里面的方法都是抽象的象。
抽象类中的方法可以是抽象的,也可以不是抽象的。
所有类都直接或者间接的继承自Object类。Object类是所有类的超类。
(6)案例
某培训机构的老师有基础班的,也有就业班的。
共性:
属性:姓名,年龄
功能:讲课。
现在又要针对日语这种小语种单独开班,需要部分基础班老师和部分就业班老师会说日语。
请用所学知识把上面的内容用代码体现。
老师
基础班老师
部分基础班老师类
就业班老师
部分就业班老师类
interface Speakjapanese
{
public abstract void speak();
}
abstract class Teacher
{
private String name;
private int age;
public Teacher(){}
public void setName(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
public void setAge (int age)
{
this.age=age;
}
public int getAge()
{
return age;
}
//睡觉的方法
public void sleep()
{
System.out.println("睡觉");
}
//吃饭的方法
public void eat()
{
System.out.println("吃饭");
}
}
//定义基础班老师的抽象类
abstract class BaseTeacher extends Teacher
{
public BaseTeacher(){}
public abstract void teach();
}
//定义就业班老师的抽象类
abstract class AdvanceTecher extends Teacher
{
public void AdvanceTeacher(){}
public abstract void teach();
}
//教日语类基础班的老师类
class JapaneseAbseTeacher extends Teacher implements Speakjapanese
{
public JapaneseAbseTeacher(){}
public void speak()
{
System.out.println("教日语类基础班的老师学习日语");
}
public void teach()
{
System.out.println("教日语类基础班的老师教javaSE");
}
}
//教日语类就业班的老师类
class JapaneseAdvanceTeacher extends Teacher implements Speakjapanese
{
public JapaneseAdvanceTeacher(){}
public void speak()
{
System.out.println("教日语类就业班的老师学习日语");
}
public void teach()
{
System.out.println("教日语类就业班的老师教javaEE");
}
}
//教非日语类基础班的老师类
class NotJapaneseAbseTeacher
{
public void teach()
{
System.out.println("教非日语类基础班的老师教javaSE");
}
}
class NotJapaneseAdvanceTeacher
{
public void teach()
{
System.out.println("教非日语类就业班的老师教javaEE");
}
}
class TeacherTest
{
public static void main(String[] args)
{
//教日语类基础班的老师
JapaneseAbseTeacher jat=new JapaneseAbseTeacher();
jat.setName("刘亦菲");
jat.setAge(25);
System.out.println(jat.getName()+"***"+jat.getAge());
jat.speak();
jat.teach();
//教日语类就业班的老师
JapaneseAdvanceTeacher j=new JapaneseAdvanceTeacher();
j.setName("成龙");
j.setAge(60);
System.out.println(j.getName()+"***"+j.getAge());
j.speak();
j.teach();
}
}
3:包:其实就是文件夹。用于区分相同的类名。
格式:
package 包名;
包名:全部小写,可以单级包,也可以多级包。
顺序问题:
package -- > import -- > class
带包的类该如何编译和运行呢?
方式1:手动建包
A:用javac命令编译生成class文件。
B:手动创建包(文件夹)。
C:包class文件扔到文件夹中。
D:用java命令执行
类一定要用全路径名称。
带着包使用。
java com.PackageDemo
方式2:自动建包
编译的时候,让它自动建包。
javac -d . PackageDemo.java
-d 后面. 表示在当前目录建立包。
如果包名太长,用的次数比较多的时候,就麻烦了。
所以,这个时候,才会出现导包技术:
格式:
import 包名1.包名2...类名;
四种权限修饰符的访问权限
本类 | 同包(无关类或者子类) | 不同包(子类) | 不同包(无关类) | |
private | Y | |||
默认 | Y | Y | ||
protected | Y | Y | Y | |
public | Y | Y | Y | Y |
推荐:
成员变量 private
构造方法 public
成员方法 public
4:不同修饰符修饰的内容( 和内部类无关)
类 | 成员变量 | 成员方法 | 构造方法 | |
private | Y | Y | Y | |
默认 | Y | Y | Y | Y |
protected | Y | Y | Y | |
public | Y | Y | Y | Y |
abstract | Y | Y | ||
static | Y | Y | ||
final | Y | Y | Y |
注意,常见规则如下:
以后,所有的类都用public修饰。并且,在一个java文件中,只写一个类。
以后,所有的成员变量用private修饰。
以后,所有的成员方法用public修饰。
如果是抽象类或者接口:
public abstract + ...
以后,所有的构造方法用public修饰。
如果类是工具类或者单例类:
构造用private修饰
(1)把类定义在一个类的内部。
(2)访问特点:
A:内部类可以直接访问外部类成员,包括私有
B:外部类要想访问内部类成员,必须创建对象。
(3)内部类分类:
A:成员位置
private 安全
static 方便调用
B:局部位置
定义在方法中。
局部内部类访问局部变量必须加final修饰。
延迟生命周期。
class Outer
{
private int num = 10;
class Inner
{
public void show()
{
System.out.println(num);
}
}
public void method()
{
Inner i = new Inner();
i.show();
}
}
class InnerTest
{
public static void main(String[] args)
{
//Outer o = new Outer();
//o.method();
//我能不能直接使用Inner类呢
//Inner i = new Inner();
//i.show();
//可以用,但是必须加限定。
//格式:
//外部类名.内部类名 变量 = 外部类对象.内部类对象;
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
(4)匿名内部类(掌握) A:是定义在局部位置的没有名字的内部类。
B:前提
存在一个类,抽象类,或者接口。
C:格式
new 类或者接口名()
{
重写方法;
}
本质理解:其实这是一个继承类或者实现接口的匿名的子类对象。
D:使用
当你看到方法的形式参数是接口或者抽象类的时候。
用匿名内部类改进。(集合,IO,awt)
什么时候使用匿名内部类呢?
一般来说,当接口或者抽象类中的方法在3个以下的时候。考虑使用匿名内部类。
以后在你看到一个方法接收的形式参数是一个抽象类或者接口的时候。
就可以考虑采用匿名内部类实现。
interface Inter
{
public abstract void show();
public abstract void show2();
}
class Outer
{
public void method()
{
new Inter()
{
public void show()
{
System.out.println("show");
}
};
new Inter()
{
public void show()
{
System.out.println("show");
}
public void show2()
{
System.out.println("show2");
}
}.show();
new Inter()
{
public void show()
{
System.out.println("show");
}
public void show2()
{
System.out.println("show2");
}
}.show2();
//多态
Inter i = new Inter()
{
public void show()
{
System.out.println("show");
}
public void show2()
{
System.out.println("show2");
}
};
i.show();
i.show2();
}
}
class InnerTest4
{
public static void main(String[] args)
{
Outer o = new Outer();
o.method();
}
}