面向对象概述
面向对象思想是从现实世界客观存在的事物出发来构造软件系统。对象是现实生活中实际存在的事物;类是由相同类型的对象共有的特征和行为归纳构成的。
而面向对象的思想就是把现实世界中的对象所具有的特征和行为抽象出来形成一个类,再根据实际业务来创建对象,然后通过对象间的相互操作模拟真实业务需求。
对象特征->属性或成员变量
对象行为->方法或函数
面向对象程序设计的基本特征
抽象
抽象类、抽象方法
概念:当一个类没有足够明确的信息来描述刻画对象时,这个类定义为抽象类;
当一个方法不能明确如何实现时,这个方法定义为抽象方法;抽象方法的目的是将那些共有的、但不能具体实现的行为抽出来,形成抽象方法;从而为子类规定了统一的规范,也可以实现多态;
定义:[修饰符] abstract class 类名{ //抽象类体}
[修饰符] abstract class 方法名([参数列表]) //抽象方法没有方法体
抽象类和抽象方法的说明:
1、抽象类中的抽象方法数目大于等于0;
2、抽象类不能被实例化,抽象类可以被继承,不能被定义成final类;
3、继承抽象类的类必须实现抽象类的抽象方法,否则也需要被定义为抽象类;
4、一个类实现某个接口,但没有实现该接口的所有方法,则必须定义成抽象类;
案例:写一个Shape抽象类,从中写获取面积和周长的抽象方法,并写出相应的圆和长方形的实现类,并输出其面积和周长
import java.math.BigDecimal;
import java.math.RoundingMode;
abstract class Shape {
public abstract double getArea();
public abstract double getPerimeter();
}//建立一个抽象类,用来存放获取面积和周长的抽象方法
class Circle extends Shape{
private double r;
public Circle(double r) {
this.r=r;
}
@Override
public double getArea() {
// TODO Auto-generated method stub
return Math.PI*r*r;
}
@Override
public double getPerimeter() {
// TODO Auto-generated method stub
return 2*Math.PI*r;
}
}//Shape的Circle的实现类,重写其中的抽象方法
class Rectangle extends Shape{
private double x;
private double y;
public Rectangle(double x,double y) {
this.x=x;
this.y=y;
}
@Override
public double getArea() {
// TODO Auto-generated method stub
return x*y;
}
@Override
public double getPerimeter() {
// TODO Auto-generated method stub
return (x+y)*2;
}
}//Shape的Rectangle的实现类,重写其中的抽象方法
public class Test{
public static void main(String[] args) {
Circle cir=new Circle(2);
Rectangle rec=new Rectangle(2,3);
double cirarea=cir.getArea();
double cirperimeter=cir.getPerimeter();
double recarea=rec.getArea();
double recperimeter=rec.getPerimeter();
//直接输出结果不保留小数
System.out.println("圆的面积为:"+cirarea);
System.out.println("圆的周长为:"+cirperimeter);
System.out.println("长方形的面积为:"+recarea);
System.out.println("长方形的周长为:"+recperimeter);
System.out.println("--------------------");
//输出结果保留两位小数
BigDecimal two1 = new BigDecimal(cirarea);
two1 = two1.setScale(2, RoundingMode.HALF_UP);
System.out.println("圆的面积为:"+two1);
BigDecimal two2 = new BigDecimal(cirperimeter);
two2 = two2.setScale(2, RoundingMode.HALF_UP);
System.out.println("圆的周长为:"+two2);
BigDecimal two3 = new BigDecimal(recarea);
two3 = two3.setScale(2, RoundingMode.HALF_UP);
System.out.println("长方形的面积为:"+two3);
BigDecimal two4 = new BigDecimal(recperimeter);
two4 = two4.setScale(2, RoundingMode.HALF_UP);
System.out.println("长方形的周长为:"+two4);
}
}
向上转型
向上转型时一种多态的体现是,是指将子类的对象转成父类的对象
public static void main(String[] args) {
Shape shape1=new Circle(3);//向上转型
System.out.println("shape1.getArea()="+shape1.getArea());
Shape shape2=new Rectangle(2,3);//向上转型
System.out.println("shape2.getPerimeter()="+shape2.getPerimeter());
Circle c1=(Circle)shape1;//向下转型
System.out.println("c1.getArea()="+c1.getArea());
}
向上转型是指将一个子类的对象转成父类的对象,不需要强制类型转换,转换安全;
向下转型是指将一个父类的对象转成子类的对象,需要强制类型转换,转换不安全;
//常规代码形式,所用案例是求一组圆的面积的和与一组长方形的面积的和
public class TestShape1 {
//这个方法是用来实现一组圆的面积的和的计算
public double sumCircle(Circle[] circles) {
double sum=0;
for(int i=0;i<circles.length;i++) {
sum+=circles[i].getArea();
}
return sum;
}
//这个方法是用来实现一组长方形的面积的和的计算
public double sumRectangle(Rectangle[] rectangles) {
double sum=0;
for(int i=0;i<rectangles.length;i++) {
sum+=rectangles[i].getArea();
}
return sum;
}
public static void main(String[] args) {
Circle[] c=new Circle[2];
Rectangle[] r=new Rectangle[2];
c[0]=new Circle(3);
c[1]=new Circle(2);
r[0]=new Rectangle(2,3);
r[1]=new Rectangle(1,2);
//由于sumShape是实例方法,需要创建对象来调用相应的方法
TestShape1 ts=new TestShape1();
System.out.println("sumCircle="+ts.sumCircle(c));
System.out.println("sumRectangle="+ts.sumRectangle(r));
}
}
//用向上转型简化代码并计算图形面积的和
public class TestShape2 {
//用sumShape的方法实现计算一组图形的面积,图形不只是圆,还有长方形
public double sumShape(Shape[] shapes) {
double sum=0.0;
for(int i=0;i<shapes.length;i++) {
sum+=shapes[i].getArea();
}
return sum;
}
public static void main(String[] args) {
Shape[] sh=new Shape[4];
sh[0]=new Circle(2);
sh[1]=new Circle(3);
sh[2]=new Rectangle(2,3);
sh[3]=new Rectangle(1,4);
TestShape2 ts=new TestShape2();
System.out.println("sumShape="+ts.sumShape(sh));
}
}
接口
Java语言中的接口是一些抽象方法的声明,是一些抽象方法的集合,这些方法没有实现,需要具体的实现类来实现。
就虽然接口看着和抽象类差不多,但是两者还不同的,因为再Java中一个类只能有一个直接父类——单继承,所以想要增加规范的方法就需要修改父类,会使修改麻烦增加,因此引入接口这一定义来弥补单继承的缺点,使一个类能够在不改变原来继承结构上,实现多个接口。
接口与类的结构近似,但是只包含常量和抽象方法,不包含普通变量和具体方法。
定义:[public] interface 接口名 [extends 父接口名列表]{
[public] static final type varable=value;//常数列表,静态常量
[public] abstract type methodName(参数列表);//抽象方法列表
//接口必须定义为public权限或默认权限,public可以省略
}
实现:[类修饰符] class 类名[extends 父类名] [implements 接口名列表]{
成员变量定义;
成员方法定义;
}
//航行的接口
public interface IShip {
//航行速度的抽象方法
public abstract void ship(double speed);
}
//飞行的接口
public interface IPlane {
//飞行速度的抽象方法
public abstract void fly(double speed);
}
//同时继承航行和飞行的接口,接口多继承
public interface IAirBoat extends IPlane,Iship{}
//定义一个ChineseAirBoat的类用于实现接口IAirBoat
public class ChineseAirBoat implements IAirBoat{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ChineseAirBoat(String name) {
this.name=name;
}
@Override
public void fly(double speed) {
// TODO Auto-generated method stub
System.out.println("机名为:"+name+",飞行速度为:"+speed);
}
@Override
public void ship(double speed) {
// TODO Auto-generated method stub
System.out.println("机名为:"+name+",航行速度为:"+speed);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
IAirBoat airboat=new ChineseAirBoat("蛟龙-500");
//向上转型,用IAirBoat接口声明变量airboat
airboat.fly(1000);
airboat.ship(500);
IShip sh=new ChineseAirBoat("蛟龙-500");
//向上转型,用IShip接口声明变量sh
sh.ship(400);
//sh没法实现fly()的抽象方法,因为IShip中没有该抽象方法,所以没法实现
}
}
抽象类和接口区别:
抽象类:1、单继承,一个子类只能继承一个父类;
2、可以有普通方法和属性变量;
3、可以被不同修饰符修饰,可以有实例变量和类变量;
4、有构造方法,可以实例化;
接口:1、多接口,类可以实现多个接口,一个接口可以继承多个类;
2、只有常量和抽象方法;
3、成员变量默认为public、static、final的变量;
4、没有构造方法,不能实例化;
多态
接口的多种不同的实现方式即为多态;
多态性:允许父类对象设置成为一个或更多的它的子对象相等的技术,赋值后,父对象就可以根据当前赋值给它的子对象的特征以不同的方式运行。
多态的使用:1、父类的引用指向子类的对象;
2、子类的引用赋值父类的引用;
3、接口的引用指向实现类的对象;
多态:1、静态多态:静态多态是在编译时期就能决定调用哪个方法,主要通过
方法的重载【指一个类中定义多个名字相同、参数不同的方法】
2、动态多态:动态多态使在运行时期才能决定调用哪个方法,主要通过
方法的覆盖【子类覆盖父类的方法】
public int add(int a,int b){
return a+b;
}
public double add(double a,double b){
return a+b;
}
//这两个方法即为方法重载
内部类
实例成员内部类
实例成员内部类定义在类体内部、方法外部,与实例变量地位一致,属于外部类对象所有,存在于对象的内存空间。
内部类对象建立:
外部类 外部类对象名 = new 外部类构造方法(实参列表);
外部类.内部类 内部类对象名 = 外部类对象名.new 内部类构造方法(实参列表);
public class Outer {
String name;//类的实例变量
static String country="China";//类的类变量
public Outer(String name) {
this.name=name;
}
public void print() {
System.out.println("Outer的print方法");
new Inner().print();
}
public class Inner {
public void print() {
System.out.println("name"+name);
System.out.println("country"+country);
}
}
}
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Outer outer=new Outer("张三");
outer.print();
//创建内部类的对象
Outer.Inner inner=outer.new Inner();
inner.print();
}
}
静态内部类
把内部类定义成static,则该内部类就成为静态内部类,静态内部类存在于外部类的内存空间,而不是外部类对象的内存空间,所以静态内部类不能访问外部类的实例变量和实例方法,只能访问外部类的static的成员变量和成员方法;
创建静态内部类的语法:
外部类.内部类 对象名 = new 外部类.内部类(实参列表)
匿名内部类
没有名字的内部类
把创建的对象和定义的内部类的类体同时进行
格式:new 父类构造方法(参数列表){//匿名内部类的类体部分}