抽象
1. 抽象类
- 抽象类不能实例化, 只作为父类让子类去继承实现.
- 抽象类不一定有抽象方法, 但是有抽象方法的类一定是抽象类. 抽象类可以有普通方法.
- 一个类继承了抽象类,必须重写所有的抽象方法,或者把这个类也定义成抽象类.
示例:
package Warren;
abstract class Person{
abstract void show();
void walk(){
System.out.println(" person walk");
}
}
class Student extends Person{
@Override //继承并重写抽象方法
public void show(){
System.out.println("student show");
}
}
public class Main {
public static void main(String[] args) {
Student s1 = new Student();
s1.show();
s1.walk();//继承并实现普通方法
}
}
2. 抽象方法
- 没有方法体,只有方法声明(签名).
示例:
abstract class Shape {
abstract void draw(); // 抽象方法
}
class Circle extends Shape {
@Override
void draw() {
System.out.println("Drawing a Circle");
}//如果不重写,就报错
}
class Rectangle extends Shape {
@Override
void draw() {
System.out.println("Drawing a Rectangle");
}//如果不重写,就报错
}
public class Main {
public static void main(String[] args) {
Shape circle = new Circle();
circle.draw();
Shape rectangle = new Rectangle();
rectangle.draw();
}
}
3.模板设计方法
- 可以减少重复的代码量.
package Warren;
public abstract class Person {
public final void write(){
System.out.println("Person write");
writeMain();
System.out.println("Person write finished");
}
abstract void writeMain();
}
package Warren;
public class Teacher extends Person {
@Override
void writeMain() {
System.out.println("teacher write main");
}
}
package Warren;
public class Student extends Person {
@Override
void writeMain() {
System.out.println("student write main");
}
}
package Warren;
public class Main {
public static void main(String[] args) {
Student student = new Student();
Teacher teacher = new Teacher();
student.write();
System.out.println("-----------");
teacher.write();
}
}
- 模板方法前加final,防止子类重写使其失效.
接口(Interface)
注意点:
- 接口里面只能有抽象方法和成员变量. 接口里面的方法都是抽象方法(省略了abstract). 成员变量都是常量.
- 接口不能创建实例化对象.
- 一个类可以实现多个接口, 一个类实现接口需要重写接口中全部的抽象方法. 或者把这个类也定义成抽象类.
- 接口中的方法默认使用public修饰,以便于其他类去实现接口中的方法.
- 接口中的方法和成员变量不能用private修饰,因为接口是为了定义公共的API供其他类去实现.
接口的好处:
- 弥补了类单继承的不足,一个类可以实现多个接口.
- 让程序可以面向接口编程. 更好的切换业务实现.
package Warren;
public interface Person {
String name="man";
String getName();//无论写不写abstract,接口中的方法都是抽象方法
}
package Warren;
public class Student implements Person {
@Override
public String getName() {
return name;
}
}
package Warren;
public class Main {
public static void main(String[] args) {
System.out.println(Person.name);//可以直接访问到接口中的成员变量
Student student = new Student();
System.out.println(student.getName());
//Person p=new Person();//报错,接口不能创建实例对象
}
}
- 示例:
//Javabean
package Warren;
public class Student {
private String name;
private char gender;
private double score;
public Student() {
}
public Student(String name, char gender, double score) {
this.name = name;
this.gender = gender;
this.score = score;
}
/**
* 获取
* @return name
*/ public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return gender
*/ public char getGender() {
return gender;
}
/**
* 设置
* @param gender
*/
public void setGender(char gender) {
this.gender = gender;
}
/**
* 获取
* @return score
*/ public double getScore() {
return score;
}
/**
* 设置
* @param score
*/
public void setScore(double score) {
this.score = score;
}
public String toString() {
return "Student{name = " + name + ", gender = " + gender + ", score = " + score + "}";
}
}
//定义接口
package Warren;
import java.util.ArrayList;
/*
* author: Warren */public interface StudentOperate {
void printInfo(ArrayList<Student> students);
void printAvg(ArrayList<Student> students);
}
//实现接口的第一个方法
package Warren;
import java.util.ArrayList;
/*
* author: Warren */public class StudentOperateImp implements StudentOperate {
@Override
public void printInfo(ArrayList<Student> students) {
for (Student student : students) {
System.out.println(student.toString());
}
}
@Override
public void printAvg(ArrayList<Student> students) {
double sum = 0;
for (Student student : students) {
sum+= student.getScore();
}
double avg = sum/students.size();
System.out.println(avg);
}
}
//第二个方法
package Warren;
import java.util.ArrayList;
/*
* author: Warren */public class StudentOperateImp1 implements StudentOperate {
int countm=0,countw=0;
@Override
public void printInfo(ArrayList<Student> students) {
for (Student student : students) {
if(student.getGender()=='m'){
countm++;
}
if(student.getGender()=='w'){
countw++;
}
}
System.out.println("male is "+countm+" "+"woman is "+countw);
}
@Override
public void printAvg(ArrayList<Student> students) {
double sum = 0,max=students.get(0).getScore(),min=students.get(0).getScore();
for (Student student : students) {
if(student.getScore()>max){
max=student.getScore();
}
if(student.getScore()<min){
min=student.getScore();
}
sum+=student.getScore();
}
double avg = (sum-max-min)/(students.size()-2);
System.out.println("avg is "+avg);
}
}
//测试类
package Warren;
import java.security.PublicKey;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Student>students=new ArrayList<>();
students.add(new Student("james",'m',99));
students.add(new Student("talor",'w',19));
students.add(new Student("warren",'m',80));
students.add(new Student("ricci",'w',80));
StudentOperate studentOperateImp1=new StudentOperateImp1();//接口的好处在于这,只需修改一处即可完成功能的切换
studentOperateImp1.printInfo(students);
System.out.println("\n");
studentOperateImp1.printAvg(students);
}
}
接口新特性:
- 默认方法:jdk8以后出现,默认被public修饰
public default void print(){}
不能实例化接口去调用默认方法,需要使用实现类对象调用.
好处是扩展接口的功能时,实现类不用再重写接口中的抽象方法.
- 私有方法:必须使用private修饰,jdk9开始支持.
private void test(){}
和默认方法一样,需要使用实现类对象调用方法, 可以通过其他方法去调用该方法(因为是private的).
- 静态方法:必须使用static修饰,默认被public修饰,写不写都可以
static void test(){}
接口的多继承
- 一个接口可以继承多个接口
interface a{
void sayHello();
}
interface b {
void print();
}
//一个接口可以继承多个接口
interface c extends a,b{
}
//通过使用接口的多继承,类可以更好的实现接口中的功能
class d implements c{
@Override
public void sayHello() {
}
@Override
public void print() {
}
}
使用接口的注意事项
- 一个接口继承多个接口,如果这些接口中的方法签名冲突(重载),则不支持多继承
interface a{
void sayHello();
}
interface b {
String sayHello();
}
//报错,此时不支持多继承
interface c extends a,b{
}
- 一个类实现多个接口,如果这些接口中的方法签名冲突,则不支持多实现
interface a{
void sayHello();
}
interface b {
String sayHello();
}
//一个接口可以继承多个接口
class c implements a,b{
}
- 如果一个类在继承了父类的情况下又实现了接口,而且父类和接口中有重名的方法,子类会优先调用父类中的.