一.封装:
1.概述:
我们日常使用的电脑主机,把CPU、内存、主板等都封装到机箱里面去,假如没有机箱的话,这些会全部散落在一起,开机也没有开机按钮,需要我们直接操作跳线才能把电脑开启。一旦操作不慎会让机器损坏。
(1)如果我们用机箱把它们封装起来,就不需要这样做了,体现了封装的——安全特性。
(2)当我们想要给电脑加内存的时候,我们可以直接把电脑给维修的人,等他加好内存之后。我们拿到手的还是那个机箱,里面发生了怎样的变化我们也不知道。体现了封装的——将变化隔离。
(3)在机箱里面提供一个开机按钮,而不需要我们直接使用跳线开机,体现了封装的——便于使用。
(4)只要机箱提供了开机功能,无论这个机箱拿到哪里去,都可以使用这个开机功能,体现了封装的——提供重复性。
2.补充:权限修饰符
权限修饰符就是控制变量的可见范围的。
(1)public:公共的。public修饰的成员变量或者方法任何人都可以直接访问。
(2)private:私有的。private修饰的成员变量或者方法只能在本类中进行直接访问。
3.封装的步骤:
(1)使用private修饰需要被封装的属性。
(2)提供一个公共的方法设置或者获取该私有的成员属性。
命名规范:
set属性名( );
get属性名( );
4.封装一定要提供get或者set方法吗?
不一定,要根据需求来定。比如说女性的年龄如果不想对外界显示,那么就不用对外提供get方法。
5.封装的规范:在现实开发中,一般实体类的所有成员属性(成员变量)都要封装起来。
注解:①实体类:实体类就是用于描述一类事物的就称作为实体类。
②类大体上可以分为实体类或工具类。
6.封装的好处:
(1)提高数据的安全性。
(2)操作简单。操作简单是相对调用者而言的。
(3)隐藏了实现,调用者不用关心被调用者内部的方法是怎么写的。如果调用这个方法出错,也是被调用者去改代码。
7.实例
需求:使用Java类描述一个计算器类,计算器具有操作数1,操作数2,操作符三个公共的属性,还具备计算的功能行为。要求不能对操作数1,操作数2,运算符这些属性进行直接的赋值,要封装起来。
分析:我们只需要提供set方法即可,不用提供get方法。字符串需要使用"equals",而+、-、*、/是字符,属于基本数据类型,只要使用“==”即可。
class Calculator{
private int num1; //操作数1
private int num2; //操作数2
private char option; //运算符
//提供公共的方法设置属性值……
public void initCalculator(int n1,int n2,char o){
num1 = n1;
num2 = n2;
if(o == '+'||o == '-'||o == '*'||o == '/'){
option = o;
}else{
option = '+';
}
}
//计算的功能
public void calculate(){
switch(option){
case '+':
System.out.println("做加法运算,结果是:"+(num1+num2));
break;
case '-':
System.out.println("做减法运算的结果是:"+(num1-num2));
break;
case '*':
System.out.println("做乘法运算的结果是:"+(num1*num2));
break;
case '/':
System.out.println("做除法运算的结果是:"+(num1/num2));
break;
}
}
}
class Demo2{
public static void main(String[] args){
//创建了一个计算器对象
Calculator c = new Calculator();
//设置属性值
c.initCalculator(1,2,'+');
//调用计算器的计算功能
c.calculate();
}
}
运行结果如下图所示:
二.继承
1.存在的问题:
(1)如果没有继承,会出现类和类的关系无法描述;
(2)如果没有继承,类和类之间有关系会出现类和类的描述代码的重复;
2.定义:
继承是通过关键字extends体现的,继承可以理解为某种事物是另一种事物的一种;
3.格式:
class 类名1 extends 类名2 {
}
4.继承要注意的事项:
(1) 千万不要为了减少重复代码而去继承,只有真正存在着继承关系的时候才去继承。例如人和狗虽然都有名字,但是他们没有继承关系;
(2) 父类私有的成员不能被继承。现实生活中父亲的东西也不能全部都继承下来,分家的时候也肯定会留下养老金,那些东西是属于他个人的,你不能继承;再比如父亲的年龄如果不用private修饰也是可以继承的,但是年龄是属于他私人的,不能继承就需要用private修饰,用private修饰年龄属性后,子类对象就不能使用了。
(3) 父类的构造函数不能被继承。构造方法是用来初始化这个类的成员属性的,就算子类把它继承下来也没有意义。因为这个功能只有在父类中才有作用;
(4) 创建子类对象时默认会先调用父类无参的构造函数。
5.实例:
class Person{
String name;
private int age;
public Person(String name){
this.name = name;
}
public Person(){
System.out.println("Person类的构造方法被调用了....");
}
public void eat(){
System.out.println(name+"在吃饭...");
}
}
//学生类
class Student extends Person { // Student 就称作为Person类的子类, Person类就称作为Student的父类 //(超类、基类)
int num; //学号
public Student(){
System.out.println("Student类的构造方法被调用了....");
}
public void study(){
System.out.println(name+"good good study , day day up");
}
}
class Demo1 {
public static void main(String[] args) {
Student s = new Student();
}
}
运行结果如下图所示:
6.继承的特点:
(1)描述类和类之间的关系;
(2)降低类和类之间的重复代码;
7.注意:
(1)降低对象和对象之间的代码重复可以使用静态变量,降低类和类之间的代码重复可以使用继承;
(2)父类的构造函数不能被继承,但并不是说父类的构造函数不能被调用,调用和继承是没有任何关系的。
比如说Demo1和Student两个类也没有继承关系,但是在Demo1中new了Student对象后,在Demo1中是可以调用Student类中的方法。
8.调用父类的构造方法是可以初始化从父类继承下去的属性的。
三.多态
1.定义:通俗的说多态就是一个对象具备多种形态。专业的说法是:父类的引用类型变量指向了子类的对象,或者是接口的引用类型变量指向了接口实现类的对象。
2.多态的前提:必须存在继承或者实现的关系。
3.多态要注意 的细节:
(1) 多态情况下,子父类存在同名的成员变量(不管是静态还是非静态)时,访问的是父类的成员变量。(如果是普通方式,访问的是子类的)
(2) 多态情况下,子父类存在同名的非静态的成员函数时,访问的是子类的成员函数。(如果是普通方式,访问的是子类的)
(3) 多态情况下,子父类存在同名的静态的成员函数时,访问的是父类的成员函数。
(4) 多态情况下,不能访问子类特有的成员。
和Java编译器的运行原理有关,Java编译器在一编译的时候就会检查这个引用类型变量a所属的这个类Animal是否有指定的成员dig(),如果没有就会马上报错。
普通情况下都是看左边的,只有在非静态函数的情况下才是看右边的。
总结:多态情况下,子父类存在同名的成员时,访问的都是父类的成员,除了在同名非静态函数时才是访问子类的。
4.疑问:为什么不能访问子类特有的成员?
与Java编译器的原理有关,编译看左边,运行不一定看右边。
Java编译器在编译的时候,会检查引用类型变量所属的类是否具备指定的成员,如果不具备马上编译报错。
5.实例:
//动物类
abstract class Animal{
String name;
String color = "动物色";
public Animal(String name){
this.name = name;
}
public abstract void run();
public static void eat(){
System.out.println("动物在吃..");
}
}
//老鼠
class Mouse extends Animal{
String color = "黑色";
public Mouse(String name){
super(name);
}
public void run(){
System.out.println(name+"四条腿慢慢的走!");
}
public static void eat(){
System.out.println("老鼠在偷吃..");
}
//老鼠特有方法---打洞
public void dig(){
System.out.println("老鼠在打洞..");
}
}
class Fish extends Animal {
public Fish(String name){
super(name);
}
public void run(){
System.out.println(name+"摇摇尾巴游..");
}
}
class Demo1{
public static void main(String[] args) {
Animal a = new Mouse("老鼠");//可以理解为别人要一个动物对象,这时候给他一个老鼠,完 //全符合现实中的说法。
//a.dig();会报错。
a.eat();
}
}
运行结果如下图所示:
6.多态的应用:
(2) 多态用于返回值类型的时候,可以返回更多类型的数据。
(1) 多态用于形参类型的时候,可以接收更多类型的数据 。(需求1)
7.多态的好处:提高了代码的拓展性。
8.实例一
(1) 需求:定义一个函数可以接收任意类型的图形对象,并且打印图形面积与周长。
(2) 实例:
//图形类
abstract class MyShape{
public abstract void getArea();
public abstract void getLength();
}
class Circle extends MyShape{
public static final double PI = 3.14;
double r;
public Circle(double r){
this.r =r ;
}
public void getArea(){
System.out.println("圆形的面积:"+ PI*r*r);
}
public void getLength(){
System.out.println("圆形的周长:"+ 2*PI*r);
}
}
class Rect extends MyShape{
int width;
int height;
public Rect(int width , int height){
this.width = width;
this.height = height;
}
public void getArea(){
System.out.println("矩形的面积:"+ width*height);
}
public void getLength(){
System.out.println("矩形的周长:"+ 2*(width+height));
}
}
class Demo1 {
public static void main(String[] args) {
Circle c = new Circle(4.0);
print(c);
Rect r = new Rect(3,4);
print(r);
}
public static void print(MyShape s){ // MyShpe s = new Circle(4.0);
s.getArea();
s.getLength();
}
}
(3) 运行结果
9.实例二
(1) 需求:定义一个函数可以返回任意类型的图形对象。
(2) 实例:
//图形类
abstract class MyShape{
public abstract void getArea();
public abstract void getLength();
}
class Circle extends MyShape{
public static final double PI = 3.14;
double r;
public Circle(double r){
this.r =r ;
}
public void getArea(){
System.out.println("圆形的面积:"+ PI*r*r);
}
public void getLength(){
System.out.println("圆形的周长:"+ 2*PI*r);
}
}
class Rect extends MyShape{
int width;
int height;
public Rect(int width , int height){
this.width = width;
this.height = height;
}
public void getArea(){
System.out.println("矩形的面积:"+ width*height);
}
public void getLength(){
System.out.println("矩形的周长:"+ 2*(width+height));
}
}
class Demo1 {
public static void main(String[] args) {
MyShape m = getShape(0); //调用了使用多态的方法,定义的变量类型要与返回值类型一致。
m.getArea(); //此时不能写rect,因为只是要返回一个图形,而这个图形不一定是矩形,如果这样写会报错,
m.getLength();
}
public static MyShape getShape(int i){
if (i==0){
return new Circle(4.0);
}else{
return new Rect(3,4);
}
}
}
(3) 运行结果
10.接口关系下的多态:
(1) 实现关系下的多态:
接口 变量 = new 接口实现类的对象;
(2) 实例:
interface Dao{
//接口的方法全部都是非静态的方法。存在同名的非静态方法永远是调用子类的,所以接口中也是调用实现类的方法
public void add();
public void delete();
}
//接口的实现类
class UserDao implements Dao{
public void add(){
System.out.println("添加成功!!");
}
public void delete(){
System.out.println("删除成功!!");
}
}
class Demo1 {
public static void main(String[] args) {
//实现关系下的多态
Dao d = new UserDao(); //接口的引用类型变量指向了接口实现类的对象。
d.add();
}
}
(3) 运行结果