把昨天的拿过来一点
封装
**基本概念**
通常情况下可以在测试类给成员变量赋值一些合法但不合理的数值,无论是编译阶段还是运行阶段都不会报错或者给出提示,此时与现实生活不符。为了避免上述错误的发生,就需要对成员变量进行密封包装处理,来隐藏成员变量的细节以及保证成员变量数值的合理性,该机制就叫做封装。
**实现流程**
(1)私有化成员变量,使用private关键字修饰;
(2)提供公有的get和set方法,并在方法体中进行合理值的判断;
(3)在构造方法中调用set方法进行合理值的判断;
实体类的封装:
在项目开发中,通常com.XXXX.bean;com.XXXX.domain;com.XXXX.entity;com.XXXX.pojo
这些包当中通常情况下存放的都是实体类。
实体类封装的步骤:
1、私有化成员变量;
2、提供公有的get/set方法
3、提供无参/有参/全参的构造方法
4、重写toString()、equals和hashCode()
案例:编程实现Person类的封装,特征有:姓名、年龄、国籍,要求提供打印所有特征的方法。
编程实现PersonTest类,在main方法中使用有参方式创建两个Person类型的对象并打印特征。
举一个Person来看一下
public class Person {
private String name;
private int age;
public void show(){
System.out.println("你的名字是:");
System.out.println(name);
System.out.println("你的年龄是:");
System.out.println(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (0 < age && age < 150){
this.age = age;
}else {
age = 18;
System.out.println("你输入的年龄有误");
}
}
public Person(){}
public Person(String name, int age) {
setName(name);
setAge(age);
}
public static void main(String[] args) {
Person person = new Person();
person.show();
person.setName("小菜鸡");//这里就是传进去类似于初始化name和age懂吧,这就是调用了set方法传进去,是输出不了结果的懂吧,这里是我没反应过来的点;下面输出结果是下面的show方法运行的结果。
person.setAge(30);
person.show();
}
}
写的时候相对应着,private私有化成员变量;
get set方法
**继承
公共类中已有特征和行为而在多个类型只需要编写自己独有特征和行为的机制,叫做继承。
使用继承提高了代码的复用性,可维护性以及扩展性。
在Java语言中使用extends(扩展)关键字来表示继承关系。
java 只支持单继承,可以有多重继承,一个子类只能有一个父类,而一个父类可以有多个子类(简单来说就是一个孩子一个爹,一个爹可以有多个孩子)
注意:**子类 is a 父类**
注意事项
(1)子类不能继承父类的构造方法和私有方法,但私有成员变量可以被继承只是不能直接访问。
(2)无论使用何种方式构造子类的对象时都会自动调用父类的无参构造方法,来初始化从父类
中继承的成员变量,相当于在构造方法的第一行增加代码:super()的效果。
(3)使用继承必须满足逻辑关系:子类 is a 父类,也就是不能滥用继承。
(4)Java语言中只支持单继承不支持多继承,也就是说一个子类只能有一个父类,但一个父类
可以有多个子类。
### 方法的重写(Override)
方法的重载(方法名相同,参数类型,个数,顺序不同)
(1)基本概念
从父类中继承下来的方法不满足子类的需求时,就需要在子类中重新写一个和父类一样的方法
来覆盖从父类中继承下来的版本,该方式就叫做方法的重写。
(2)重写的原则
a.要求方法名相同、参数列表相同以及返回值类型相同,从jdk1.5开始允许返回子类类型。
b.要求方法的访问权限不能变小,可以相同或者变大。
c.要求方法不能抛出更大的异常(异常机制)。
练习:
编程实现Animal类的封装,特征有:名字和毛色,要求提供打印所有特征的方法。
编程实现Dog类的封装并继承自Animal类,该类的特征有:牙齿数量,要求提供打印所有特征的方法
编程实现DogTest类,在main方法中分别使用无参和有参方式构造Dog类型对象并打印特征。
这个简单看看例子体会一下
public class Animal { public Animal(String name, String color) { this.name = name; this.color = color; } public Animal() { } private String name; private String color; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public void show(){ System.out.println("我的名字叫做" + getName() + ",颜色是" +getColor()); } }
public class Dog extends Animal { private int teethnumber; public Dog() { } public Dog(String name, String color, int teethnumber) { super(name, color); this.teethnumber = teethnumber; } public Dog(int teethnumber) { this.teethnumber = teethnumber; } }
public class Dogtest { public static void main(String[] args) { Dog dog = new Dog(); dog.setColor("白色"); dog.setName("小黑"); dog.show(); Dog dog1 = new Dog("小白","黑色",20); dog1.show(); } }
2.访问权限
2.1 常用的访问权限//重要
#### 访问控制符 访问权限 本类内部 本包中的类 子类内部 其它包中的类
```java
public 公有的 ok ok ok ok
protected 保护的 ok ok ok no
啥也不写 默认的 ok ok no no
private 私有的 ok no no no
```
a.public修饰的成员可以在任意位置使用;
b.private修饰的成员只能在本类内部使用;
c.通常情况下,成员方法都使用public关键字修饰,成员变量都使用private关键字修饰;
### 包的声明
package 包名; - 表示声明单层包
package 包名1.包名2.包名3...包名n; - 表示多层包,为了便于管理以及解决命名冲突的问题;
**final关键字
final关键字用于修饰属性、效(标变为了常量,无法再对其再次进行赋值)final修饰的局部变量,只能赋值- -次(可以先声明后赋值)
final修饰的成员变时,必须在声明时赋值。
final关键字用于修饰类
final修饰类,可以被继承
final关键字用于修饰方法
final修饰方法,不允许被子类写
全局常量(public static final)
全鋦常量的命名规范:
由一个或多个单词组成,单词与单词之间必须使用下划线隔开,单词中所有字母大写。
### 多态
**基本概念**
多态主要指同一种事物表现出来的多种形态。
饮料:可乐、雪碧、乐虎、加多宝、红牛、脉动、...
宠物:猫、狗、鸟、小强、鱼、...
人:学生、教师、工人、保安、...
**语法格式**
父类类型 引用变量名 = new 子类类型(); //父类型的引用指向子类型的对象 【多态的核心】
如:
Person pw = new Worker();
Shape shape = new Rect();
pw.show();
练习:
编程实现Person类的封装,特征有:姓名和年龄,要求提供打印所有特征的方法。
编程实现Worker类的封装并继承自Person类,特征有:薪水
编程实现PersonWorkerTest类,在main方法中分别创建Person和Worker类型对象并打印特征。
我都摆出来,主要理解test类
package person2; public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public Person() { } 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; } public void show(){ System.out.println("name :" + getName() + ", age :" + getAge()); } }
package person2; public class Worker extends Person{ private double salary; public Worker(String name, int age, double salary) { super(name, age); this.salary = salary; } public Worker() { } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } @Override public void show(){ System.out.println("name : " + getName() + " , age: " + getAge() + " , salary :" + getSalary()); } }
package person2; public class PersonWorkerTest { public static void main(String[] args) { Person person = new Person("xaiohei",26); Worker worker = new Worker("xaiobai",24,54000); person.show(); worker.show(); Person person1 =new Worker("xaiofen",24,64000); person1.show(); } }
******核心********父类型的引用指向子类型的对象 【多态的核心】
解析:
由程序结果可知,编译阶段调用Person类中的show方法,运行阶段调用Worker类中的show方法
**多态的效果**
(1)当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调用父类独有的方法;
(2)当父类类型的引用指向子类类型的对象时,父类类型的引用不可以直接调用子类独有的方法;
(3)对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类重写的版本;
(4)对于父子类都有的静态方法来说,编译和运行阶段都调用父类版本;
**引用数据类型之间的转换**
(1)引用数据类型之间的转换方式有两种:自动类型转换 和 强制类型转换。
其中自动类型转换主要指小类型向大类型的转换,也就是子类转换为父类。
其中强制类型转换主要指大类型向小类型的转换,也就是父类转换为子类。
(2)引用数据类型之间的转换必须发生在父子类之间,否则编译报错。
(3)若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运行阶段发生类型转换异常。
(4)为了避免上述错误的发生,应该在强转之前进行判断,格式如下:
if(引用变量 instanceof 数据类型) - 判断引用变量指向的对象是否为后面的数据类型
**实际意义**
多态的实际意义在于屏蔽不同子类的差异性实现通用的编程带来不同的效果。
抽象类
抽象类必须使用abstract class声明
-个抽象类中可以没有抽象方法。抽象方法必须写在抽象类或者接口中。
格式:
abstract class 名{ 1/ 抽象类
抽象方法
只声明而未实现的方法称为抽象方法(未实现指的是:没有“{}”方法体),抽象方法必须使用abstract关键字声明。
格式:
abatract class 类名{ // 抽象类
public abstract void 方法名() ;
1 抽象方法,只声明而未实现不能被实例化
在抽象类的使用中有几个原则:
抽象类本身是不能直接进行实例化操作的,即:不能直接使用关键字new完成。
一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)则必须覆写(重写)抽象类中的全部抽象方法。
常见问题
1、抽象类能否使用final声明?
不能,因为fina1属修饰的类是不能有子类的,而抽象类必须有子类才有意义,所以不能。
2、 抽象类能否有构造方法?
能有构造方法,而且子类对象实例化的时候的流程与普通类的继承是一样的, 都是要先调用父类中的构造方法(默认是无参的),之后再调用子类自己的构造方法。
抽象类和普通类的区别
1、抽象类必须用public或protectea修饰 (如果为private修饰,那么子类则无法继承,也就无法实现其抽象方法)。默认缺省为public
2、抽象类不可以使用new关键字创建对象,但是在子类创建对象时, 抽象 父类也会被JVM实例化。
3、如果一个子类继承抽象类,那么必须实现其所有的抽象方法。如果有未实现的抽象方法,那么子类也必须定义为abstract类
看个例子
创建一个抽象类Person,创建一个实体类Nurse,然后去重写Person的抽象方法;
package person; public abstract class Person { private String name; private int age; private double height; public Person(String name, int age, double height) { this.name = name; this.age = age; this.height = height; } public Person() { System.out.println("这是person的无参构造方法"); } public abstract void say(); }
package person; public class Nurse extends Person{ public Nurse() { System.out.println("nurse无参"); } @Override//一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)则必须覆写(重写)抽象类中的全部抽象方法 public void say() { System.out.println("哈哈"); } }
package person; public class Persontest { public static void main(String[] args) { Nurse nurse = new Nurse(); //多态 } }
子类对象实例化的时候的流程与普通类的继承是一样的, 都是要先调用父类中的构造方法(默认是无参的),之后再调用子类自己的构造方法
所以在创建一个新对象后Nurse nurse = new Nurse(),会先调用父类的构造方法,再调用子类的,,感兴趣的话,可以去执行一下上述代码。
接口.
概念.如果一个类中的全部方法都是抽象方法, 全部属性都是全局常量,那么此时就可以将这个类定义成一个接口。定义格式:
interface接口名称{
全局常量;
抽象方法;
面向接口编程思想
这种思想是接口是定义(规范,约束)与实现(名实分离的原则)的分离。
优点:
降低程序的耦合性易于程序的扩展有利于程序的维护
全局常量和抽象方法的简写
因为接口本身都是由全局常量和抽象方法组成,所以接口中的成员定 义可以简写:1、全局常量编写时,可以省略public static final 关键字,例如:public static final String INFO = "内容”;
简写后:
String INFO = "内容"
2、抽象方法编写时,可以省略 public abstract关键字, 例如:public abstract void print() ;
简写后:
void print() ;
接口的实现implements
接口可以多实现:
格式:
class子类implements 父接口1,父接口2...{
以上的代码称为接口的实现。那么如果一个类即要实现接口, 又要继承抽象类的话,则按照以下的格式编写即可:cla3s子类extends父类implements 父接口1,父接口2...{
接口的继承
接口因为都是抽象部分,不存在具体的实现,所以允许多继承, 例如:interface C extends A,B{
注意
如果-个接口要想使用,必须依靠子类。子类 (如果不是抽象类的话)要实现接口中的所有抽象方法。
面试题:接口和抽象类的区别
1、抽象类要被子类继承,接口要被类实现。
2、接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法。
3、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
4、 抽象类使用继承来使用, 无法多继承。 接口使用实现来使用, 可以多实现
5、 抽象类中可以包含static方法 ,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明静态方法)
6、接口不能有构造方法,但是抽象类可以有
看一个例子
定义一个Runner接口有跑的方法,再定义一个Hunter接口继承Runner有捕猎的方法,
创建一个Chinese类实现Hunter接口,再去创建一个类去实现
public interface Runner { void runnning(); }
public interface Hunter extends Runner{ void hunt(); }
public class Chinsee implements Hunter{ @Override public void hunt() { System.out.println("抓到一只小白兔"); } @Override public void runnning() { System.out.println("我在跑"); } }
public class ChineseTest { public static void main(String[] args) { //接口类型的引用指向实现类的对象,形成多态 Runner runner = new Chinsee(); runner.runnning(); Hunter hunter = new Chinsee(); hunter.hunt(); hunter.runnning(); } }
嗯看看就行,理解一下
呜啊啊,寒假实训第四天,头有点小晕,再去熬一天