栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java学习笔记(抽象类和接口)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java学习笔记(抽象类和接口)

Java学习笔记(抽象类和接口)
    • 学习说明
    • 抽象类和接口
      • 抽象类
        • 为什么要用抽象类
        • 抽象类的注意点
      • 举例讲解
      • 接口
      • Comparable举例讲解
      • ActionListener接口
      • Cloneable接口
      • 接口与抽象类
      • 将基本数据类型作为对象处理
      • 对一个对象数组排序
      • 大数值计算BigInteger、BigDecimal类
      • Rational类

学习说明
要点:
	了解抽象类的简单使用
	了解为什么要使用抽象类
	了解抽象类使用的注意点
	了解接口的基本使用
	熟悉组件监听事件的添加
	了解 clone 方法
	了解接口与抽象类的区别
	了解对对象数组进行排序的使用(这里还存在着问题,代码运行不正确)
	熟悉大数类(BigInteger、BigDecimal)的使用


学习资料为:《Java语言程序设计》梁勇
抽象类和接口 抽象类
抽象方法:不能实现

抽象类里面只要有抽象方法就好了,不需要每个方法都是抽象方法
UML里面抽象方法用斜体表示(抽象类、属性也是斜体)
public abstract class GeometricObject {
	protected String color;
	protected boolean filled;
	protected Date dateCreated;
	
	public GeometricObject() {
		// TODO Auto-generated constructor stub
		dateCreated = new Date();
	}
	
	public GeometricObject(String color, boolean filled) {
		// TODO Auto-generated constructor stub
		dateCreated = new Date();
		this.color = color;
		this.filled = filled;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public boolean isFilled() {
		return filled;
	}

	public void setFilled(boolean filled) {
		this.filled = filled;
	}

	public Date getDateCreated() {
		return dateCreated;
	}
	
	public String toString() {
		return "created on " + dateCreated + "ncolor" + color + "and filled" + filled;
	}
	
	public abstract double getArea();   // 有抽象方法的类就是抽象类
	
	public abstract double getPerimeter();
}
为什么要用抽象类
为了更简单的设计,看下面
// 继承GeometricObject的第一个类Circle
public class Circle extends GeometricObject {

	private double radius;
	
	public Circle() {
		// TODO Auto-generated constructor stub
		setRadius(1.0);
	}
	
	public Circle(double radius) {
		// TODO Auto-generated constructor stub
		this.radius = radius;
	}
	
	public Circle(double radius, String color, boolean filled) {
		// TODO Auto-generated constructor stub
		super(color, filled);
		this.radius =radius;
	}
	
	@Override   // 继承抽象类则必须要实现抽象方法,除非继承的类也是抽象类
	public double getArea() {
		// TODO Auto-generated method stub
		return radius * radius * Math.PI;
	}

	public double getRadius() {
		return radius;
	}

	public void setRadius(double radius) {
		this.radius = radius;
	}

	@Override
	public double getPerimeter() {
		// TODO Auto-generated method stub
		return 2 * radius * Math.PI;
	}
}

// 继承GeometricObject的第二个类Rectangle
public class Rectangle extends GeometricObject {
	private double width;
	private double height;
	
	public Rectangle() {
		// TODO Auto-generated constructor stub
		width = 2.0;
		height = 1.0;
	}
	
	public Rectangle(double width, double height) {
		// TODO Auto-generated constructor stub
		this.width = width;
		this.height = height;
	}
	
	public Rectangle(double width, double height, String color, boolean filled) {
		// TODO Auto-generated constructor stub
		super(color, filled);
		this.width = width;
		this.height = height;
	}
	
	@Override // 实现了抽象方法
	public double getArea() {
		// TODO Auto-generated method stub
		return width * height;
	}

	@Override
	public double getPerimeter() {
		// TODO Auto-generated method stub
		return 2 * width + 2* height;
	}

	public double getWidth() {
		return width;
	}

	public void setWidth(double width) {
		this.width = width;
	}

	public double getHeight() {
		return height;
	}

	public void setHeight(double height) {
		this.height = height;
	}
}
// 抽象类和上面一样
// 测试主函数
public static void main(String[] args) {
    GeometricObject object1 = new Circle(5);
    GeometricObject object2 = new Rectangle(4, 3);
    
    System.out.println("The two objects have the same area? " + equalArea(object1, object2));
    
    displayGeometricObject(object1);
    
    displayGeometricObject(object2);
}

// 这里进行函数书写的时候,参数会少很多,且类型更统一,方便理解
public static boolean equalArea(GeometricObject object1, GeometricObject object2) {
    return object1.getArea() == object2.getArea();
}

public static void displayGeometricObject(GeometricObject object) {
    System.out.println();
    System.out.println("The area is " + object.getArea());
    System.out.println("The perimeter is " + object.getPerimeter());
}
抽象类的注意点
抽象类可以不包含抽象方法,但是如果有抽象方法,则该类必须为抽象类(后面讲到的接口也可以)

父类不是抽象类,但子类是可以为抽象类的(这样的用法不多)
对于方法也是如此,父类中不是抽象的方法,在子类中也可以改为抽象的
举例讲解
以日历类 Calender 和 GregorianCalender 

Calender类的域常量
    YEAR
    MONTH
    DATE
    HOUR
    HOUR_OF_DAY
    MINUTE
    SECOND
    DAY_OF_WEEK
    DAY_OF_MONTH
    DAY_OF_YEAR
    WEEK_OF_MONTH
    WEEK_OF_YEAR
    AM_PM(0表示上午,1表示下午)
// 直接通过 Calender.属性 获得的值并不一定正确,都很奇怪,需要采用get进行获取
public static void main(String[] args) {
    System.out.println(Calendar.YEAR);
    System.out.println(Calendar.MONTH);
    System.out.println(Calendar.DATE);
    System.out.println(Calendar.HOUR);
    System.out.println(Calendar.HOUR_OF_DAY);
    System.out.println(Calendar.MINUTE);
    System.out.println(Calendar.SECOND);
    System.out.println(Calendar.DAY_OF_WEEK);
    System.out.println(Calendar.DAY_OF_MONTH);
    System.out.println(Calendar.DAY_OF_YEAR);
    System.out.println(Calendar.WEEK_OF_MONTH);
    System.out.println(Calendar.WEEK_OF_YEAR);
    System.out.println(Calendar.AM_PM);
}


// 正确的获取方式
public static void main(String[] args) {
    Calendar calendar = new GregorianCalendar(); // 采用公历计数
    
    System.out.println(calendar.get(Calendar.YEAR));
    System.out.println(calendar.get(Calendar.MONTH));
    System.out.println(calendar.get(Calendar.DATE));
    System.out.println(calendar.get(Calendar.HOUR));
    System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
    System.out.println(calendar.get(Calendar.MINUTE));
    System.out.println(calendar.get(Calendar.SECOND));
    System.out.println();
    System.out.println(calendar.get(Calendar.DAY_OF_WEEK));
    System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
    System.out.println(calendar.get(Calendar.DAY_OF_YEAR));
    System.out.println(calendar.get(Calendar.WEEK_OF_MONTH));
    System.out.println(calendar.get(Calendar.WEEK_OF_YEAR));
    System.out.println(calendar.get(Calendar.AM_PM));
}
// 注意月份,月份从0开始,为0-11
接口
接口里面只包含常量和抽象方法

接口和抽象类很像,但也有一些区别,例如可多实现接口,但只能继承一个类

实现接口同样需要实现全部方法(应该是抽象方法的,但接口里面的方法都是抽象的),但如果是抽象类实现接口的话,则不要求
// 定义一个接口
public interface Edible {
	
	public abstract String howToEat();
}


class Animal{
	
}

// Chicken既继承类又实现接口(这个书写顺序不能乱,要先继承,再实现接口)
class Chicken extends Animal implements Edible{

	@Override
	public String howToEat() {
		// TODO Auto-generated method stub
		return "Chicken fry it";
	}
	
}

// 用于对照的
class Tiger extends Animal{
	
}

// 抽象类实现接口,可以不用实现方法
abstract class Fruit implements Edible{
	
}

// 但下面的具体类就需要实现了
class Apple extends Fruit{

	@Override
	public String howToEat() {
		// TODO Auto-generated method stub
		return "Apple make apple pie";
	}
	
}

class Orange extends Fruit{

	@Override
	public String howToEat() {
		// TODO Auto-generated method stub
		return "Orange make orange juice";
	}
	
}


// 测试主函数
public static void main(String[] args) {
    Object[] objects = {new Tiger(), new Chicken(), new Apple()};
    
    for (int i = 0; i < objects.length; i++) {
        if(objects[i] instanceof Edible)
            System.out.println(((Edible)objects[i]).howToEat());    // 要十分注意这个类型转换的括号,"."运算符的优先级最高,所以需要把前面的转化部分都括起来
        else {
            System.out.println("is not instanceof Edible");
        }
    }
}
接口的常量的理解
    书写方面,其实省略书写是没问题的,编译器自动补全了

属性可以通过 接口名.属性来访问(因为是静态的)
// 下面两种写法是一致的
public interface Edible {
	public static int NUM = 4;
	
	public abstract String howToEat();
}

public interface Edible {
	int NUM = 4;
	
	String howToEat();
}

// 测试主函数
public static void main(String[] args) {
    System.out.println(Edible.NUM);
}
Comparable举例讲解
// 接口
public interface Comparable {
	int compareTo(Object object);
}

// Max类的写法,这里直接传入参数Comparable对象,是为了有更好的鲁棒性
// 简单来说,如果不是这个类型,则编译就会报错,如果在后面进行类型转化后再比较就只能在运行时才会报错了
public class Max {
	public static Comparable max(Comparable comparable1, Comparable comparable2) {
		if(comparable1.compareTo(comparable2) > 0)
			return comparable1;
		return comparable2;
	}
}

// 一个矩形类,实现接口,进行比较
public class ComparableRectangle implements Comparable {

	private double width;
	private double height;
	
	public ComparableRectangle(double width, double height) {
		// TODO Auto-generated constructor stub
		this.width = width;
		this.height = height;
	}
	
	@Override
	public int compareTo(Object object) {
		// TODO Auto-generated method stub
		if(this.getArea() > ((ComparableRectangle)object).getArea())
			return 1;
		else if(this.getArea() < ((ComparableRectangle)object).getArea())
			return -1;
		return 0;
	}

	public double getArea() {
		return width * height;
	}
}

// 测试主函数
public static void main(String[] args) {
    ComparableRectangle rectangle1 = new ComparableRectangle(3, 4);
    ComparableRectangle rectangle2 = new ComparableRectangle(2, 6);
    ComparableRectangle rectangle3 = new ComparableRectangle(3, 5);
    
    System.out.println(rectangle1.compareTo(rectangle2));
    System.out.println(rectangle1.compareTo(rectangle3));
    System.out.println(rectangle3.compareTo(rectangle2));
}
ActionListener接口
按钮触发事件,监听器的使用
public class HanldleEvent extends JFrame {
	
	public static void main(String[] args) {

		JFrame frame = new HanldleEvent();
		frame.setTitle("Handle Event");
		frame.setSize(300, 200);
		frame.setLocation(200, 100);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
	
	public HanldleEvent() {
		// TODO Auto-generated constructor stub
		JButton jbtnOK = new JButton("OK");
		JButton jbtnCancel = new JButton("Cancel");
		
		JPanel panel = new JPanel();
		panel.add(jbtnOK);
		panel.add(jbtnCancel);
		
		add(panel);
		
		OKListenerClass listener1 = new OKListenerClass();
		CancelListenerClass listener2 = new CancelListenerClass();
		jbtnOK.addActionListener(listener1);
		jbtnCancel.addActionListener(listener2);
	}
}

// 创建监听器类,实现了执行方法函数
class OKListenerClass implements ActionListener{
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		System.out.println("OK button clicked");
	}
}

class CancelListenerClass implements ActionListener{
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		System.out.println("Cancel button clicked");
	}
}
Cloneable接口
下面演示原有的clone方法
public static void main(String[] args) {
    Calendar calendar = new GregorianCalendar(2022, 5, 21);
    Calendar calendar1 = calendar;
    Calendar calendar2 = (Calendar)calendar.clone();    // 这里复制的是内容,创建了新的对象
    
    System.out.println("calender == calender1 is " + (calendar == calendar1));
    System.out.println("calender == calender2 is " + (calendar == calendar2));
    
    System.out.println("calender equals calender1 is " + calendar.equals(calendar1));
    System.out.println("calender equals calender2 is " + calendar.equals(calendar2));
}
接下来自己写一个覆盖掉原有的clone方法
// 创建一个House类
public class House implements Cloneable, Comparable {
	private int id;
	private double area;
	private Date buildDate;
	
	public House(int id, double area) {
		// TODO Auto-generated constructor stub
		this.id = id;
		this.area = area;
		buildDate = new Date();
	}
	
	public int getId() {
		return id;
	}

	public double getArea() {
		return area;
	}

	public Date getBuildDate() {
		return buildDate;
	}

    // 这里实现了父类的方法,但实现的是浅复制,即只是复制每个内在对象的引用,但又生成了一个新的对象
    // 这个方法如果不重写,则会在后面运行的时候报错
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}

	@Override
	public int compareTo(Object object) {
		// TODO Auto-generated method stub
		if(area > ((House)object).area)
			return 1;
		else if(area < ((House)object).area)
			return -1;
		return 0;
	}
	
	public void printInfo() {
		System.out.println(id);
		System.out.println(area);
		System.out.println(buildDate);
	}
}

// 测试主函数
public static void main(String[] args) throws CloneNotSupportedException {
    House house1 = new House(1, 100);
    House house2 = (House) house1.clone();
    
    house1.printInfo();
    house2.printInfo();
    
    // 不管是 == 还是 equals 返回都是false
    System.out.println("house1 == house2 is " + (house1 == house2));
    System.out.println("house1.equals(house2) is " + house1.equals(house2));
    
    // 但每个内在对象(属性),返回的都是true
    System.out.println("house1.getArea() == house2.getArea() is " + (house1.getArea() == house2.getArea()));
    System.out.println("house1.getBuildDate() == house2.getBuildDate() is " + (house1.getBuildDate() == house2.getBuildDate()));
    System.out.println("house1.getId() == house2.getId() is " + (house1.getId() == house2.getId()));
}
接口与抽象类
抽象类的修饰符没有限制
但接口的修饰符
    变量必须为public static final修饰
    方法必须为public abstract修饰

类只能单继承,但接口可以多扩展,类可以实现多个接口,接口之间也可以多个扩展
// 类的继承与实现接口
public class NewClass extends BaseClass implements Interface1, Interface2 …… InterfaceN{

}

//
public interface NewInterface extends Interface1, Inetrface2 …… InterfaceN{

}
使用场景:
    强关系的(父子关系)用类的继承
    弱关系的(类属关系,即对象拥有某种属性)用接口
还是很抽象啊,一般接口可以为形容词,类则为名词,描述具有属性的,则用接口(Comparable)

接口可以定义不相关类的共有父类型,比抽象类更加灵活
    这里就很抽象了,应该和上面那个使用场景结合在一起理解
    关系弱,很多类具有相同的属性,例如可比较
    (其实不用太纠结,以后写着写着慢慢修改就好)
将基本数据类型作为对象处理
出于对性能的考虑,Java并没有把基本数据类型作为对象使用
    但在一些场景需要考虑通用性,就可以这么干了(也正是因为基本数据类型都有包装类)
对一个对象数组排序
类实现Comparable接口

这里的问题很奇怪,没有进行compareTo的重写,就很迷惑
public class GenericSort {

	public static void main(String[] args) {

		Integer[] intArr = {new Integer(4), new Integer(3), new Integer(2), new Integer(5) };

		Double[] doubleArr = {new Double(1.2), new Double(2.3), new Double(12), new Double(10)};

		Character[] charArr = {new Character('A'), new Character('D'), new Character('C'), new Character('B')};

		String[] stringArr = { "Hello", "hello", "abcd" };

		sort(intArr);
		sort(doubleArr);
		sort(charArr);
		sort(stringArr);

		printList(intArr);
		printList(doubleArr);
		printList(charArr);
		printList(stringArr);
	}

	public static void sort(Comparable[] list) {
		Comparable currentMin;
		int currentMinIndex;

		// 采用选择排序进行排序
		for (int i = 0; i < list.length - 1; i++) {
			currentMin = list[i];
			currentMinIndex = i;

			for (int j = i + 1; j < list.length; j++) {
				if (currentMin.compareTo(list[j]) > 0) {
					currentMin = list[i];
					currentMinIndex = j;
				}
			}

			if (currentMinIndex != i) {
				list[currentMinIndex] = list[i];
				list[i] = currentMin;
			}
		}
	}

	public static void printList(Object[] list) {
		for (int i = 0; i < list.length; i++) {
			System.out.print(list[i] + " ");
		}
		System.out.println();
	}
}
大数值计算BigInteger、BigDecimal类
基本使用如下:
// 这里不能采用普通的加减乘除,需要调用函数进行计算
public static void main(String[] args) {
	BigInteger bigInteger = new BigInteger("1234567890");
	BigInteger bigInteger2 = new BigInteger("3");
	
	System.out.println(bigInteger.multiply(bigInteger2));
	
	BigDecimal bigDecimal = new BigDecimal(1.0);
	BigDecimal bigDecimal2 = new BigDecimal(3);
	
	// 这个表示取10位小数,最后一个进位
	System.out.println(bigDecimal.divide(bigDecimal2, 10, BigDecimal.ROUND_UP));
}
阶乘计算如下:
public class Test {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.println("Please input a num : ");
		int num = scanner.nextInt();
		
		System.out.printf("%e", getFactorial(num));
	}
	
	public static double getFactorial(int num) {
		BigInteger result = BigInteger.ONE;
		for (int i = 1; i <= num; i++) {
			result = result.multiply(new BigInteger(i + ""));
		}
		return result.doubleValue();	// 转化为浮点数数值类型,但同时也就不能够计算过大的数字了
	}
}
Rational类
有理数类(自己创建的一个类,复习一下前面的知识)
// 蛮长,蛮细节的一个类
public class Rational {
	private long numerator = 0;
	private long denominator = 1;

	public Rational() {
		// TODO Auto-generated constructor stub
		this(0, 1);
	}

	public Rational(long numerator, long denominator) {
		// TODO Auto-generated constructor stub
		long gcd = gcd(numerator, denominator);
		this.numerator = ((denominator > 0) ? 1 : -1) * numerator / gcd;
		this.denominator = Math.abs(denominator) / gcd;
	}

	public long getNumerator() {
		return numerator;
	}

	public long getDenominator() {
		return denominator;
	}

	public Rational add(Rational secondRational) {
		long n = numerator * secondRational.getDenominator() + denominator * secondRational.getNumerator();
		long d = denominator * secondRational.getDenominator();
		return new Rational(n, d);
	}

	public Rational subtract(Rational secondRational) {
		long n = numerator * secondRational.getDenominator() - denominator * secondRational.getNumerator();
		long d = denominator * secondRational.getDenominator();
		return new Rational(n, d);
	}

	public Rational multiply(Rational secondRational) {
		long n = numerator * secondRational.getNumerator();
		long d = denominator * secondRational.getDenominator();
		return new Rational(n, d);
	}

	public Rational divide(Rational secondRational) {
		long n = numerator * secondRational.getDenominator();
		long d = denominator * secondRational.getNumerator();
		return new Rational(n, d);
	}

	public String toString() {
		if (denominator == 1)
			return numerator + "";
		else {
			return numerator + "/" + denominator;
		}
	}

	public long gcd(long n, long d) {
		long n1 = Math.abs(n);
		long n2 = Math.abs(d);
		long gcd = 1;

		for (int i = 1; i <= n1 && i <= n2; i++) {
			if (n1 % i == 0 && n2 % i == 0)
				gcd = i;
		}
		return gcd;
	}
	
	public boolean equals(Object parm) {
		if((this.subtract((Rational)parm)).getNumerator() == 0)
			return true;
		return false;
	}
	
	public int intValue() {
		return (int)doubleValue();
	}
	
	public float floatValue() {
		return (float)doubleValue();
	}
	
	public double doubleValue() {
		return numerator * 1.0 / denominator;
	}
	
	public long longValue() {
		return (long)doubleValue();
	}
	
	// 这里需要注意括号的位置,实际这个类并不难理解,只是初中,甚至小学的数学知识
	public int compareTo(Object object) {
		if(this.subtract((Rational)object).getNumerator() > 0)
			return 1;
		else if(this.subtract((Rational)object).getNumerator() < 0)
			return -1;
		return 0;
	}
}

// 测试主函数
// 结果符合一般的分数运算规则,注意精度,这里的精度达不到太高,且long类型长度有限制
public static void main(String[] args) {
	Rational rational1 = new Rational(3, 5);
	Rational rational2 = new Rational(1, 2);
	
	System.out.println(rational1.add(rational2));
	System.out.println(rational1.subtract(rational2));
	System.out.println(rational1.multiply(rational2));
	System.out.println(rational1.divide(rational2));
	
	System.out.println(rational1.intValue());
	System.out.println(rational1.floatValue());
	System.out.println(rational1.doubleValue());
	System.out.println(rational1.longValue());
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/924505.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号