面向对象的三大特征
1.封装
封装
隐藏实现细节,对外只提供公共访问的访问方式;
在java中封装的体现:
1)方法:
对方法的实现不用考虑其怎么实现的,只要告知了我们方法的名称 参数类型
作用和返回值类型,这个方法我们就能使用;
2)对象:
对象就封装了数据和功能,只要拿到这个对象,就能使用这个对象的数据个和功能了;
3)私有化类的成员属性,对外给属性提供公共的getXxx/setXxx方法去间接的给属性
取值和赋值;
怎么取值怎么赋值不是我们关心的,我们只关系get方法可以取到值,set方法可以赋值
就可以了;
1.1. 类成员的访问控制
对于类的成员(属性、方法)的访问控制,四种修饰符都可以使用
每种权限修饰的成员的使用范围见图
类:
默认,public,final,abstract
我们自己定义:public居多
成员变量:
四种权限修饰符均可,final,static
我们自己定义:private居多
构造方法:
四种权限修饰符均可,其他不可
我们自己定义:public 居多
成员方法:
四种权限修饰符均可,fianl,static,abstract
我们自己定义:public居多
代码如下:
public class Demo4
{
public static void main(String[] args){
/*
Employee emp1 = new Employee();
emp1.name = "jack";
emp1.age = -10;
//jack -10 程序的执行没有问题,而是程序不符合生活逻辑问题;
emp1.show();
System.out.println("=======================");
*/
/*
//判断处理
int age = -10;
if(age>=0 && age<=120){//合法年龄
emp1.age = age;
}else{//非法年龄
emp1.age = 0;
}
emp1.show();
System.out.println("----------------------");
Employee emp2 = new Employee();
emp2.name = "rose";
//判断处理
age = -20;
if(age>=0 && age<=120){
emp2.age = age;
}else{
emp2.age = 0;
}
emp2.show();
//代码复用性问题
System.out.println("-----------------------");
*/
Employee emp3 = new Employee();
emp3.name = "smith";
emp3.setAge(-20);
emp3.show();
//emp3.age = -20;
//emp3.show();
//如果使用员工对象的封装方法setAge()去给员工的age属性赋值,就能对员工年龄进行逻辑
//判断再赋值的效果;但是仍然可以使用 对象.属性 的方式给员工的age属性赋值呀,那么问题
//又回到一开始的问题了;
//问题是:只能去使用员工对象的setAge()方法进行逻辑判断并给age属性赋值,而不让使用
//对象.属性 的方式去给员工对象的age属性赋值;
emp3.setAge(22);
emp3.show();
System.out.println("-----------------------------");
Student s = new Student();
s.setSno(101);
s.setName("jack");
s.setAge(21);
s.show();
System.out.println(s.getSno()+" "+s.getName()+" "+s.getAge());
}
}
//员工描述类
class Employee
{
//成员属性
String name;
private int age;
//成员方法
public void show(){
System.out.println(name+" "+age);
}
/*
对年龄的判断进行了一个方法的封装,就能提高代码复用性了,同时
将这个方法给定成了员工的功能方法,即就是只要是个员工(对象)都
具有该功能;
*/
public void setAge(int a){
if(a>=0 && a<=120){
age = a;
}else{
age = 0;
}
}
}
class Student
{
//成员属性
private int sno;
private String name;
private int age;
//get/set
public void setSno(int no){
sno = no;
}
public int getSno(){
return sno;
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
public void setAge(int a){
age = a;
}
public int getAge(){
return age;
}
//成员方法
public void show(){
System.out.println(sno+" "+name+" "+age);
System.out.println(getSno()+" "+getName()+" "+getAge());
}
}
2.继承
继承
当多个类有共同的属性和方法时,可以抽取出一个父类
继承的主要作用就是为了实现代码的复用,简化编写
注意:并不是所有的有共同属性和方法的类都可以使用继承,使用继承必须要满足一个is a
的关系
关键字:
extends
被继承的类叫父类 继承的类叫子类
1.子类继承父类的,可以将父类中所有的非私有内容继承过来
2.子类中还可以有自己的特有属性和方法
3.子类还可以重写父类的中的方法
什么时候子类需要重写父类中的方法
父类的方法不能满足子类的需求的时候
4.构造方法不能被继承
5.java中,类与类之间是单继承
6.java中所有的类都直接或间接的继承object类
如果指明了父类,间接的继承object类
如果没有指明父类,默认直接的继承object类
2.1 this关键字和super关键字
this:当前对象的使用
1.使用this区分成员变量和局部变量
2.在方法中使用this调用本类的其他方法
3.在构造方法中调用本类中调用本类的其他构造方法
super:父类对象引用
1.super可以调用父类的成员变量和方法
2.super在构造方法中调用父类的构造方法
在一个构造方法中,super()和this()不能共存
构造方法的特殊性:
当创建子类对象调用子类的对象的构造方法,会默认调用父类的无参构造方法
我们无法控制构造方法的执行顺序,总是先执行辈分大的类的构造方法
Super和this的区别
1. this在方法中调用本类的其他方法,super在方法中调用父类的方法
2. 在构造方法中,this可以在构造方法中去调用本类的其他构造方法,super在构造方法中调用父类的构造方法
3. This和super构造方法中使用的时候都必须放在构造方法代码的第一行
2.2 final修饰符
final可以修饰类、变量、方法
final修饰的类叫最终类,最终类不能被继承
String类就是最终类 不能被继承
final修饰变量,变为常量,只能被赋值一次
赋值要在创建对象之前赋值
赋值的时机:
1.声明常量的时候直接赋值
2.构造方法内赋值
3.可以在构造代码块中赋值
4.如果是静态常量还可以可以在静态代码块中赋值
final修饰的方法不能被重写
final修饰形参,形参值不能被改变
形参可以被使用,但是不能改变形参的值
instanceof 比较关键字
判断一个对象是不是一个类的对象
代码如下:
animal类
public class Animal {
private String name;
private int age;
private String sex;
public Animal() {
}
public Animal(String name) {
this.name = name;
}
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void eat(){
System.out.println(".....吃草");
}
public void sleep(){
System.out.println("....睡");
}
}
cat类
//Cat继承Animal
public class Cat extends Animal {
public void climb(){
System.out.println("....猫爬树");
}
//重写父类的eat方法
public void eat(){
System.out.println("....猫吃鱼");
}
}
dog类
//Dog继承Animal
public class Dog extends Animal {
public void look(){
System.out.println("...狗看门");
}
//重写父类的eat方法
public void eat(){
System.out.println("....狗吃骨头");
}
}
测试类
public class Test {
public static void main(String[] args) {
//创建一个Cat的对象
/*Cat c=new Cat();
c.eat();
c.sleep();
c.setName("花花");
String name=c.getName();
System.out.println(name);
c.climb();
//创建一个Dog对象
Dog d=new Dog();
d.sleep();
d.look();*/
//instanceof 判断一个对象是不是一个类的对象
Cat c=new Cat();
Dog d=new Dog();
System.out.println(c instanceof Cat);//判断对象c是不是Cat类的对象
//System.out.println(c instanceof Dog);//编译报错
System.out.println(c instanceof Animal);
Animal a=new Animal();
System.out.println(a instanceof Cat);//false
}
}
3.多态
多态:
一个事物(对象)在不同的情况下可以有不同的形态
实现多态的前提:
1.要有继承关系
2.要有子类去重写父类的方法
如果没有也可以,但是没有方法重写的多态是没有意义的
3.要有父类引用指向子类对象
多态的特点:
父类指向子类的对象
1.通过父类引用调用子类对象重写后的方法时,调用的是子类
重写后的方法
2.父类引用不能调用子类对象特有的方法
动态绑定
Animal a = new Cat();
在编译期,对于一个引用并不能确定它的具体类型,在运行期才能具体确定
它的具体类型
3.如果非要调用子类特有的方法
向上转型
将子类类型转换为父类类型----自动转换
子----父
向下转型
将父类类型转换为子类类型-----强制转换
目标类型 名 = (目标类型)引用;
编译看左边,执行看右边
只有普通方法具有多态性
final、static、private方法不具有多态性
成员变量,不具有多态性
表面上的内容它不具有多态性,实际的行为才具有多态性
多态的作用:
1.提高了程序的维护性(由继承保证)
2.提高了程序的扩展性(由多态保证)
增强for循环------for-each循环
增强for循环主要是为了 为了遍历数组或者集合中的元素
for(遍历的单个元素的数据类型 存放单个元素的变量:要遍历的集合或者是数组){
循环体
}
多态的缺点:
父类的引用不能调用子类的特有的方法
抽象:
abstract
抽象类 用abstract修饰的类 叫抽象类
如果一个类,没有具体的对象,可以将一个类定义为抽象类
抽象类的特点:
1.抽象类不能实例化
2.重选另类存在的惟一的意义就是被继承
3.有抽象方法的类一定是抽象类,但是抽象类不一定有抽象方法
4.抽象类中的可以有抽象方法,也可以有非抽象方法
抽象方法:
用abstract修饰的方法,方法只有方法的声明,没有方法的具体实现
抽象方法相当于一个规则,一个标准
指明了只要是这个类型,就要有这个功能
抽象类的成员特点:
1.抽象类可以有成员变量
2.抽象类可以有构造方法,但是不能被实例化
3.抽象类可有抽象方法,也可以有非抽象的方法
abstract不能和以下的关键字共存
private冲突,final冲突,static无意义
接口:
接口是比抽象类更抽象的东西
1.接口中所有的方法都是抽象方法
接口中定义的方法默认的访问修饰符 public abstract
2.接口没有构造方法,也不能被实例化
3.接口存在的意义就是被实现implements
4.如果一个类要实现一个接口,就需要实现接口中的所有的方法
5.抽象类中可以有抽象方法
6.抽象类可以有普通的成员变量
接口作用:
接口就是一个规则,规范
一个类实现了接口,就代表这个类遵守接口的规范
有了抽象类为什么还有接口
将抽象类中的所有方法定义成抽象方法和接口有什么区别
Java中的类的继承具有很大的局限性,java中的继承只能是单继承
一个子类只能有一个直接的父类
类实现接口是可以多实现,也就是说一个类可以实现多个接口
类和类的关系:单继承
类和接口的关系;多实现
接口和接口的关系:
多继承,一个接口可以继承多个接口
代码如下:
利用上面的animal,cat,dog类,在写一个测试类
public class Test {
public static void main(String[] args) {
/*Cat c1=new Cat();
Dog d1=new Dog();*/
//父类引用指向子类对象
Animal a1=new Cat();
a1.eat();//调用的是子类重写后的方法
a1.sleep();
//父类引用不能调用子类特有的方法
//a1.climb();
//如果非要调用子类特有的方法,使用向下转型强制的将父类类型转换为子类类型
Cat c=(Cat)a1;
c.climb();
a1.fun();
System.out.println(a1.n);//10
/*Animal a2=new Animal();
Cat c2=(Cat)a2;*/
/*Animal a3=new Dog();
Cat c3=(Cat)a3;*/
/*Cat.fun();
Animal.fun();*/
/*Animal a2=new Dog();
a2.eat();
Animal a3=new Animal();
a3.eat();*/
}
}