1. 定义
抽象类
非private访问修饰符 abstract 返回值类型 方法名(参数列表) ;
简单的说,抽象类是一个不能实例化的类,它可以具有抽象方法或者普通方法,也可以有构造方法。
普通方法和抽象方法的区别
普通方法必须要有方法体,抽象方法不能有方法体(大括号也没有);
抽象方法只能存在于抽象类/接口中,用abstract修饰,访问修饰符不能用private。
普通方法:
public void Test(){
System.out.println("hello");
}
抽象方法:
public abstract void Test(); //没有实例化,就是没有具体实现方法
抽象类和普通类有什么区别?
抽象类要用abstract修饰;普通类可以实例化,抽象类不能实例化;
抽象类体现的的是一种模板模式的设计。
抽象类:
public abstract class Person{
Person p=new Person(); //错误,不能实例化
}
普通类:
public class Person{
Person p=new Person(); //正确,普通类可以实例化
}
判断圆形和矩形的面积
//抽象类
public abstract class Shape {
public abstract void showArea();
public abstract double compare();
public boolean compareTo(GeometricObject g){
return this.compare()>g.compare();
//子类(圆形)
public class Circle extends GeometricObject {
double s;
double i;
public Circle(double i){
this.i=i;
}
@Override
public void showArea() {
s=Math.PI*i*i;
System.out.println("圆形的面积为:"+s);
}
@Override
public double compare() {
return this.s;
}
//子类(矩形)
public class Rectangle extends GeometricObject {
double w,h;
double s;
public Rectangle(double w, double h){
this.w=w;
this.h=h;
}
@Override
public void showArea() {
s=w*h;
System.out.println("矩形的面积为:"+s);
}
@Override
public double compare() {
return this.s;
}
//main方法
public class Client {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入一个数:");
double input=sc.nextDouble();
GeometricObject c=new Circle(input);
//c.showArea(input);
c.showArea();
System.out.println("请输入两个值:");
double w=sc.nextDouble();
double h=sc.nextDouble();
GeometricObject r=new Rectangle(h,w);
//r.showArea(input, w);
r.showArea();
System.out.print("圆形的面积比长方形的大吗?");
//System.out.println(c.compare()>r.compare());
System.out.println(c.compareTo(r));
}
}
结果为:
接口
接口(interface)是一种与类相似的结构,只包含常量和抽象方法。接口在许多方面与抽象类相近,但是抽象类除了包含常量和抽象方法之外,还可以包含变量和具体方法。
定义接口的语法是什么?
[public] interface 接口名{
//接口成员
}
public interface Person{
public String howToEat(); //抽象方法
}
2. 区别和联系
抽象类和接口的相同点和不同点分别是什么?
相同:
- 都位于继承的顶端,用于被其他类实现或继承;
- 自身不能实例化,都是依靠对象多态性,通过实现类/子类进行对象实例化;
- 都可以包含抽象方法,其实现类/子类都必须重写这些抽象方法;
不同:
1、抽象类体现继承关系,一个类只能单继承;接口体现实现关系,一个类可以多实现接口。
2、抽象类中可以定义非抽象方法,供子类直接使用;
3、接口中只能包含抽象方法(无须使用abstract关键字)和常量,接口中的成员都有固定修饰符。
二者的选用:
优先使用接口,尽量避免使用抽象类;
需要定义子类的行为,又要为子类提供共性功能时才考虑选用抽象类;
抽象类:
public abstract void Show{
//抽象方法
//普通方法
}
接口:
public interface Show{
//抽象方法
}
3. 抽象类的特点
- 抽象类中的方法不一定都是抽象的,抽象类中可以包含抽象的方法,也可以包含具体的方法。
- 不能实例化抽象类
例:如果Course是抽象类,则以下语句是错误的
Course c = new Course();
但是可以声明对Course对象的引用:
Course x; - 抽象类有子类的时候,除非子类采用具体的方法替代抽象类中的全部抽象方法,否则子类本身也被自动被认为是抽象的。
注意:抽象类之所以被称之为“抽象”的,是因为抽象类省略了要执行的一种或多种特定行为的细节。
总结:
判断正误
①抽象类中只能定义抽象方法。 //错误,抽象类中还可以定义普通方法
②抽象类中不能定义构造方法。
//错误,抽象类中可以定义构造方法,只是不能直接创建抽象类的实例对象而已
③抽象方法可以同时是静态方法。
//错误
abstract:用来声明抽象方法,抽象方法没有方法体,不能被直接调用,必须在子类overriding后才能使用。
static:用来声明静态方法,静态方法可以被类及其对象调用。
用static声明方法表明这个方法在不生成类的实例时可直接被类调用,而abstract方法不能被调用,两者矛盾。
④抽象类中可以没有抽象方法。但是含抽象方法的一定是抽象类。//正确
⑤声明抽象类和抽象方法都使用abstract关键字。//正确
⑥抽象类不能实例化。 //正确
⑦抽象类中可以有静态方法。 //正确 在继承实现后,在main方法中可以直接用类名调用
接口可以继承接口吗?如果可以,能继承多个吗?接口可以实现接口吗?
接口可以继承一个或多个接口;接口不能实现接口。
需求说明(练习)
实现某公司各种岗位(经理、销售人员、普通员工)的员工薪水计算。经理的薪水为基本工资+奖金,销售人员的薪水为基本工资+销售量*每件提成,普通员工只有基本工资;
要求输出不同岗位各一名员工的工资,使用抽象类实现;
分析
定义员工抽象类,具有姓名、基本工资的属性和计算薪水的抽象方法
定义子类:经理类、销售人员类、普通员工类,分别继承员工抽象类,定义各自的属性,重写计算薪水的方法
定义测试类,包含输出员工薪水的静态方法,参数为员工对象(抽象父类的引用指向子类的对象,可以实现多态)
代码:
//抽象类
public abstract class Employee {
public String name;
public double salary;
public abstract double testSalary();
}
//子类(经理)
public class Manager extends Employee {
public double prize;
public Manager(double prize,double salary,String n){
this.prize=prize;
this.salary=salary;
name = n;
}
public double testSalary() {
return salary+prize;
}
}
//子类(普通员工)
public class CommonStaff extends Employee {
public CommonStaff(double salary,String na){
this.salary=salary;
name=na;
}
@Override
public double testSalary() {
return salary;
}
}
//子类(销售人员)
public class SalesMan extends Employee {
private int num;
private double tc;
public SalesMan(int num,double tc,double salary,String n){
this.num=num;
this.tc=tc;
this.salary=salary;
name = n;
}
@Override
public double testSalary() {
return salary+num*tc;
}
}
//输出计算结果的类
public class Show {
public static void show(Employee e){
System.out.println(e.name+"的工资为:"+e.testSalary());
}
}
//main方法
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
while(true){
Employee e;
Scanner sc=new Scanner(System.in);
System.out.println("请输入你想计算什么岗位的员工工资?经理,销售人员,普通员工,退出系统");
String i=sc.nextLine();
if(i.equals("退出系统")){
System.out.println("您已经退出系统!");
break;
}else{
System.out.println("请输入"+i+"的基本工资为:");
double s=sc.nextDouble();
switch (i){
case "经理":
System.out.println("请输入"+i+"的奖金为:");
double j=sc.nextDouble();
e=new Manager(j,s,i);
Show.show(e);
break;
case "销售人员":
System.out.println("请输入"+i+"的销售量为:");
int n=sc.nextInt();
System.out.println("请输入"+i+"的提成为:");
double t=sc.nextDouble();
e=new SalesMan(n,t,s,i);
Show.show(e);
break;
case "普通员工":
e=new CommonStaff(s,i);
Show.show(e);
break;
default:
System.out.println("你输入的员工种类暂时不存在,请重新输入!");
break;
}
}
}
}
}
结果为:
内部类
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
内部类的作用
- 内部类提供了更好地封装
- 内部类成员可以直接访问外部类的私有数据
- 匿名内部类适合用于创建那些仅需要一次使用的类
1.成员内部类
成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:
public class Circle{
public static void main(String args[]){
Circle c=new Circle(14.0);//创建一个外部类对象
Circle.Draw d=c.new Draw();//创建一个内部类对象
d.drawShape();
}
double radius=0;
public Circle(double radius){
this.radius=radius;
}
class Draw{
public void drawShape(){
System.out.println(radius);
}
}
}
结果为:14.0
2. 局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
class Circle{
public static void main(String args[]){
//定义局部内部类
class inner{
int a;
}
//定義局部內部類的子类
class InnerSub extends inner{
int b;
}
InnerSub sb=new InnerSub();
sb.a=3;
sb.b=8;
System.out.println(sb.a+sb.b);
}
}
结果为:11
3. 静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
public class Circle{
private int p=5;
private static int p1=8;
static class Inner{
//静态内部类可以包含静态成员
private static int a=3;
private int c=9;
public void accout(){
//静态内部类可以访问外部类的静态成员
System.out.println(p1);
//外部类可以通过使用静态内部类的类名作为调用者来访问静态内部类的成员
System.out.println(Inner.a);
System.out.println(new Inner().c);//外部类可以使用静态内部类对象作为调用者来访问静态内部类的实例成员
}
}
public static void main(String args[]){
Circle.Inner in=new Inner();
in.accout();
}
}
结果为:8 3 9
4. 匿名内部类
匿名内部类应该是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。
interface Product{
public double getPrice();
public String getName();
}
public class Circle{
public void test(Product p){
System.out.println("购买了一个"+p.getName()+",花掉了"+p.getPrice());
}
public static void main(String[] args) {
Circle ta=new Circle();
ta.test(new Product(){
public double getPrice()
{
return 567.8;
}
public String getName()
{
return "AGP显卡";
}
});
}
}
结果为: 购买了一个AGP显卡,花掉了567.8
补充:
Ctrl+Shift+f 快捷键 可以修改eclipse的繁体字和简体字互换
v+2 可以输出一些平常不容易敲出来的字符。如图所示:
debug模式有三种:
打印 logger debug
包装类的常用方法
以Integer为例
MIN_VALUE = 0x80000000;
MAX_VALUE = 0x7fffffff;
byteValue() 取得用byte类型表示的整数
compareTo/compare 比较大小
Integer i=124; Integer j=124;
System.out.println(i==j); //true
Integer a=246; Integer b=246;
System.out.println(a==b); //false 超过了整型的范围
Integer c=258;
System.out.println(c.byteValue()); //2 取低八位的二进制值
Integer d=0x89345f0;
System.out.println(d.byteValue()); //-16 f0为11110000 1为负,-128+64+32+16+=-16
System.out.println(c.compareTo(d)); //-1 c(前者)小于d(后者) 返回-1,大于返回1,等于返回0
System.out.println(c.compare(3, 3)); //0 两者相等,返回0
System.out.println(c.compare(d, c)); //1 d>c 返回1