面向对象三大特性
面向对象的三大特性:封装,继承,多态。
封装
1.概念
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
2.代码示例
Person:
package Day4;
public class Person {
private String name;
private int age;
public Person(){
this.age=0;
this.name=null;
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return this.age;
}
public String toString(){
return "姓名:"+name+" age:"+age;
}
}
Test:
package Day4;
public class Test {
public static void main(String[] args) {
Person person=new Person();
person.setName("lyh");
person.setAge(21);
System.out.println(person);
}
}
继承
1.概念
是面向对象程序设计不可缺少的设计思想,是实现代码可重用的根基,是提高代码可扩展性的主要途径。
继承是从已有的类中派生出新的类,新的类能吸收已有类的属性和行为,并能扩展新的能力。
在JAVA中使用extends关键字来表示继承关系。
JAVA不支持多继承,单继承使JAVA的继承关系很简单,一个类只能有一个直接父类。
继承之后子类可以调用父类的所有非私有属性和非私有方法。
2.super关键字
在子类构造方法中要调用父类的构造方法,需要注意:super语句只能出现在子类构造方法体的第一行。
用“super.成员变量名”来引用父类成员变量。
用“super.方法名(参数列表)”的方式访问父类的方法。
注意:super与this的区别,this通常指代当前对象,super通常指代父类。
3.继承中的构造方法
子类构造方法总是先调用父类构造方法,默认情况下,调用父类无参构造方法。
可以在子类构造方法的第一行,使用super关键字调用父类任意一个构造方法。
如果用super,必须写在方法的第一句。
如果子类的构造方法中没有显式地调用基类构造方法,则系统默认调用基类无参数的构造方法。
原因:子类创建后需要调用父类的方法,所以在创建子类对象是父类也需要同时被创建。
4.有关继承代码测试
Animal:
package Day4;
public class Animal {
private String name;
private int age;
public Animal(){
System.out.println("Animal无参的构造方法!");
}
public Animal(String name,int age){
this();
this.name=name;
this.age=age;
System.out.println("Animal有参的构造方法!");
}
public void eat(){
System.out.println("动物吃");
}
public void getInfo(){
System.out.print("name:"+name+";"+"age:"+age);
}
}
Dog:
package Day4;
public class Dog extends Animal{
private String color;
public Dog(){
super("",0);
System.out.println("Dog无参的构造方法!");
}
public Dog(String name,int age,String color){
super(name,age);
this.color=color;
System.out.println("Dog有参的构造方法!");
}
public void getIn(){
super.getInfo();
System.out.println("color:"+color);
}
}
Test:
package Day4;
public class Test {
public static void main(String[] args) {
Dog dog=new Dog("哈哈哈",3,"黑色");
dog.getIn();
}
}
5.方法的重写(方法的覆盖)(OverRide)
在子类中可以根据需要对从基类中继承来的方法进行重写。
方法重写规则:
方法名相同、参数列表相同;
返回值类型相同;
访问权限相同
即与父类方法结构完全相同
注意:构造方法不能重写
当父类的方法实现不能满足子类需求时,可以对方法进行重写( override)。
以上一个案例为主,重写eat方法:
Animal:
package Day4;
public class Animal {
private String name;
private int age;
public Animal(){
System.out.println("Animal无参的构造方法!");
}
public Animal(String name,int age){
this();
this.name=name;
this.age=age;
System.out.println("Animal有参的构造方法!");
}
public void eat(){
System.out.println("动物吃");
}
public void getInfo(){
System.out.print("name:"+name+";"+"age:"+age);
}
}
Dog:
package Day4;
public class Dog extends Animal{
private String color;
public Dog(){
super("",0);
System.out.println("Dog无参的构造方法!");
}
public Dog(String name,int age,String color){
super(name,age);
this.color=color;
System.out.println("Dog有参的构造方法!");
}
//eat方法的重写
@Override
public void eat() {
super.eat();
System.out.println("狗吃骨头!");
}
public void getIn(){
super.getInfo();
System.out.println("color:"+color);
}
}
Test:
package Day4;
public class Test {
public static void main(String[] args) {
Dog dog=new Dog("哈哈哈",3,"黑色");
dog.getIn();
dog.eat();
}
}
6.关联与依赖
关联是“HAS”关系,依赖是“USE”关系。
A类关联B类,指的是B类对象作为A类的属性存在,称为“has”关系。
A类依赖B类,指的是B的对象作为A类的方法参数存在,称为“use”关系。
通过以下代码测试依赖关系。
Team:
//根据依赖关系团队有多名学生,而学生也有自己相应的属性
package Day5;
import java.util.Arrays;
public class Team {
private String subject;
private Student[] student;
public Team(Student[] student) {
this.student = student;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public Student[] getStudent() {
return student;
}
public void setStudent(Student[] student) {
this.student = student;
}
@Override
public String toString() {
return "Team{" +
"subject='" + subject + '\''+
","+" student=" + Arrays.toString(student) +
'}';
}
}
Student:
package Day5;
public class Student {
private String id;
private String name;
private int age;
public Student(){
this.id=null;
this.name=null;
}
public Student(String id,String name,int age){
this.name=name;
this.id=id;
this.age=age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
该团队有5名学生,并输出学生基本信息。
Test:
package Day5;
import java.lang.reflect.Array;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Student student[]=new Student[5];
student[0]=new Student("1822","cjr",21);
student[1]=new Student("1823","cyx",21);
student[2]=new Student("1825","lyh",23);
student[3]=new Student("1820","ccc",22);
student[4]=new Student("1827","jij",25);
Team team=new Team(student);
team.setSubject("智能算法");
System.out.println(team);
System.out.println(Arrays.toString(student));
System.out.println(Arrays.toString(team.getStudent()));
}
}
多态
1.概念
同一种事物,在不同时刻表现不同的状态
多态存在的三个必要条件
要有继承(包括接口的实现)(前提条件)
要有重写(前提条件)
父类引用指向子类对象
Animal:
package Day5;
public class Animal {
private String name;
private int age;
public void eat(){
System.out.println("Animal吃");
}
public static void say(){
System.out.println("Animal叫");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Dog:
package Day5;
public class Dog extends Animal{
private String type;
public void eat(){
System.out.println("Dog吃骨头");
}
public static void say(){
System.out.println("Dog旺旺");
}
public void sleep(){
System.out.println("Dog睡觉");
}
}
Cat:
package Day5;
public class Cat extends Animal{
private String type;
public void eat(){
System.out.println("cat吃饭");
}
public static void say(){
System.out.println("Cat喵喵");
}
public void study(){
System.out.println("Cat学习");
}
}
Test:
package Day5;
import java.lang.reflect.Array;
import java.util.Arrays;
public class Test {
//多态的体现
public void run(Animal animal){
animal.eat();
}
public static void main(String[] args) {
Test test=new Test();
Animal dog=new Dog();
dog.eat();//编译看左边,运行看右边。eat方法被重写
dog.say();//静态方法编译运行看左边,因为静态变量静态方法都存储在方法区。
Dog dog0=(Dog)dog;//建议在使用向下转型的时候考虑使用instanceof判断是否为该类型,避免异常。
dog0.sleep();
dog0.eat();
Animal cat=new Cat();
cat.eat();
Cat cat0=(Cat)cat;
cat0.eat();
cat0.study();
test.run(cat);
test.run(dog);
}
}
注意:对于静态方法没有必要去重写,静态方法,成员变量都是编译运行看左边。
静态加载优先于main方法。
2.final关键字
final 用于声明属性,方法和类
属性:定义就必须直接赋值或者在构造方法中进行赋值,并且后期都不能修改。
方法:子类里不可被覆盖(重写)。
类:不能被定义为抽象类或是接口,不可被继承。
在声明时同时赋值,往往与static一起使用
声明时不赋值,必须在构造方法中逐一赋值
总的原则:保证创建每一个对象的时候,final属性的值是确定的。
在方法参数前面加final关键字,为了防止数据在方法体中被修改。
package Day5;
public class keyword_final {
final static int acc=10;//必须赋值
static int num0;
final int num;//可以在构造方法中赋值
public keyword_final(int num){
this.num=num;
}
public void test(){
final int num;
}
public static void main(String[] args) {
keyword_final key0=new keyword_final(10);
keyword_final key1=new keyword_final(11);
}
}
package Day5;
public class keyword_final {
final static int a=0;//final定义的变量如果是成员变量必须初始化。
public static void main(String[] args) {
final int b=10;
System.out.println(a);
//此调用涉及静态方法只能调用静态静态标量或者静态方法。所以a必须是静态变量类似于递归算法。
}
}
3.抽象类
用abstract修饰的类就是抽象类。如果某个类中包含有抽象方法,那么该类就必须定义成抽象类。
抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。
抽象方法必须用abstract关键字进行修饰。
抽象类可以有成员属性和非抽象的成员方法。
抽象类不能被实例化,但可以有构造函数,因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。
抽象类只能用作基类,表示的是一种继承关系。继承抽象类的非抽象类必须实现其中的所有抽象方法,而已实现方法的参数、返回值要和抽象类中的方法一样。否则,该类也必须声明为抽象类。
构造方法和静态方法不可以修饰为abstract。
Shape:
package Day5;
public abstract class Shape {
int name;
public abstract double getArea();//定义抽象方法 求面积 无方法体只声明不实现 抽象类不能被实例化只能通过子类实现。
public abstract double getPerimeter();//求周长
}
Circle:
package Day5;
public class Circle extends Shape {
private double r;
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
@Override
public double getArea() {
return Math.PI*r*r;
}
@Override
public double getPerimeter() {
return 2*Math.PI*r;
}
}
Rectangle:
package Day5;
public class Rectangle extends Shape{
private double length;
private double width;
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
@Override
public double getPerimeter() {
return (length+width)*2;
}
@Override
public double getArea() {
return length*width;
}
}
Test:
package Day5;
import java.util.*;
public class Test {
public void run(Shape shape) {
System.out.println("面积:"+shape.getArea());
System.out.println("周长"+shape.getPerimeter());
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
Test test=new Test();
System.out.println("请输入圆的半径:");
double r=sc.nextDouble();
Shape circle=new Circle();
Circle c=(Circle)circle;
c.setR(r);
System.out.println("半径为:"+r+"的圆:");
test.run(circle);
System.out.println("请输入长方形的长:");
double length=sc.nextDouble();
System.out.println("请输入长方形的宽:");
double width=sc.nextDouble();
Shape rectangle=new Rectangle();
System.out.println("长度为"+length+"宽度为"+width+"的长方形:");
Rectangle re=(Rectangle) rectangle;
re.setLength(length);
re.setWidth(width);
test.run(rectangle);
}
}
instanceof在此案例中的测试出现警告
因为此案例中结果返回值一直是true。
只是修改了上一个案例的Test类方法。
package Day5;
import java.util.*;
public class Test {
public void run(Shape shape) {
System.out.println("面积:"+shape.getArea());
System.out.println("周长"+shape.getPerimeter());
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
Test test=new Test();
System.out.println("请输入圆的半径:");
double r=sc.nextDouble();
Shape circle=new Circle();
if(circle instanceof Circle) {
Circle c = (Circle) circle;
c.setR(r);
System.out.println("半径为:" + r + "的圆:");
test.run(circle);
}
System.out.println("请输入长方形的长:");
double length=sc.nextDouble();
System.out.println("请输入长方形的宽:");
double width=sc.nextDouble();
Shape rectangle=new Rectangle();
System.out.println("长度为"+length+"宽度为"+width+"的长方形:");
if(rectangle instanceof Rectangle) {
Rectangle re = (Rectangle) rectangle;
re.setLength(length);
re.setWidth(width);
test.run(rectangle);
}
}
}
4.接口
接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
接口中每一个方法也是隐式抽象的,默认为public abstract 。
接口中声明的属性默认为 public static final 的。
接口不是被类继承了,而是要被类实现。
接口不能实例化对象(无构造方法),但可以声明对象的引用。(多态性)
多个类可以实现同一个接口。
一个类可以实现多个接口,但只能继承一个类。
与继承关系类似,接口与实现类之间存在多态性。
一个接口能继承其它多个接口。
当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。
5.抽象类与接口的区别
语法上的区别
1。抽象类里可以有构造方法,而接口内不能有构造方法。
2。抽象类中可以有普通成员变量,而接口中不能有普通成员变量。
3。抽象类中可以包含非抽象的普通方法,而接口中所有的方法必须是抽象的。
4。抽象类中的抽象方法的访问类型可以是public ,protected和默认类型,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5。抽象类中可以包含静态方法,接口内不能包含静态方法。
6。抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义 静态常量。
相同点
1。抽象类和接口都不能用来创建对象。