黑马程序员-java基础(四)-面向对象(封装、继承、多态)
来源:互联网 发布:sql trigger insert 编辑:程序博客网 时间:2024/05/17 09:06
--------------- android培训、java培训、期待与您交流! ----------------
面向对象(封装、继承、多态)
1 封装
封装:隐藏对象的属性和细节,仅对外提供公共的访问方式。
好处:
1、将变化隔离,提高安全性
2、便于使用,提高重用性
原则:
1、将不需要对外提供的内容都隐藏起来
2、把属性都隐藏,提供公共方法对其进行访问
public class Test {public static void main(String[] args) {Student t=new Student();//创建对象t.setAge(30);System.out.println("age="+t.getAge());t.setAge(140);}} class Student//创建student{//private:权限修饰符,私有,不希望别人直接访问赋值,通过私有化把属性进行隐藏private int age;//对外提供方法访问隐藏的属性public void setAge(int age){//进行条件限制if(0<age&&age<120)this.age=age;elseSystem.out.println("年龄设置错误");}//对外提供方法访问隐藏属性public int getAge(){return age;}}
运行结果:
ps.
1.封装不等于私有,私有仅仅是封装的一种表现形式
2.之所以对外提供访问方式,是通过在访问方式中加入逻辑判断语句,操作数据,提高代码的健壮性
【】单例设模式
设计模式:对问题行之有效的解决方式,是一种思想
单例设计模式:保证一个类在内存中对象的唯一性
PS.
当多个程序使用一个配置对象时就需要保证该对象的唯一性
确保对象唯一性思路(代码体现):
1、禁止其他程序new一个该类对象(将构造函数私有化)
2、本类中自定义一个对象,让其他程序可以访问该类对象(在类中创建一个本类对象)
3、对外提供访问方式,让其他程序访问(提供方法获取该对象)
饿汉式
<span style="font-size:12px;">class Single{private int num;public void setNum(int num){this.num=num;}public int getNum(){return this.num;}private Single(){}//将构造函数私有化,其他程序无法创建该类对象static Single s=new Single();//创建一个本类对象//需要被其他程序调用,但是其他程序不能创建该类对象,所以要定义为静态用类名调用public static Single getInstance(){return s;}}public class Test {public static void main(String[] args) {Single s1=Single.getInstance();//通过类名调用静态方法Single s2=Single.getInstance();System.out.println(s1==s2);//验证对象的唯一性s1.setNum(10);System.out.println(s2.getNum());//验证对象的唯一性}}</span>
运行结果:
PS.
之所以不用Single.s;的方式获取Single对象,而采用getInstance获取是因为在getInstance方法中我们可以做一些判断来决定是否返回Single的对象,也就是实现了对单例对象的可控。所以,给Single的构造方法加上了private限制,禁止使用者直接采用Single.s;的方式获取。
<span style="font-size:12px;">class Single{private int num;public void setNum(int num){this.num=num;}public int getNum(){return this.num;}private Single(){}//将构造函数私有化,其他程序无法创建该类对象static Single s=null;//没有对象,调用getInstance时才创建对象//需要被其他程序调用,但是其他程序不能创建该类对象,所以要定义为静态用类名调用public static Single getInstance(){if(s==null)s=new Single();return s;}}public class Test {public static void main(String[] args) {Single s1=Single.getInstance();//通过类名调用静态方法Single s2=Single.getInstance();System.out.println(s1==s2);//验证对象的唯一性s1.setNum(10);System.out.println(s2.getNum());//验证对象的唯一性}}</span>
运行结果:
2 继承
继承:(extends 类名)
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。多个类可以称为子类,单独这个类称为父类或者超类。
1、提高代码的复用性
2、继承让类与类之间产生了关系,有了这个关系,才有多态的关系。
ps.
1、子类可以直接访问父类非私有的成员
2、子类无法继承父类私有的成员
<span style="font-size:12px;">class Person{int age=0;String name="baby";}class Student extends Person//Student继承Person类{public void study(){System.out.println(name+"...Student study....");//子类可以直接访问父类非私有成员}}public class Test {public static void main(String[] args) {Student s=new Student();s.age=3;System.out.println("name:"+s.name+"...age:"+s.age);s.study();}}</span>运行结果
PS.
继承提高了代码的复用性
PS.
java只支持单继承,不支持多继承,但支持多实现
这是因为多继承存在安全隐患,当多个父类有相同的方法时,java不知道执行哪一个
PS.
1、使用继承体系,先查阅体系父类的描述,因为父类找那个定义的是该体系中共性功能
2、在具体调用时,要创建子类的对象,因为a.父类可能不能创建对象b.创建子类对象可以使用更多的功能,包括基本的也包括特有的。
归纳:查阅父类功能,创建子类使用功能。
子父类中成员的特点
1、成员变量:子父类中类成员的特点:如果子类中出现非私有的同名成员变量时,访问本类变量用this,访问父类变量用super。
<span style="font-size:12px;">class Person{int age=5;}class Student extends Person//Student继承Person类{int age=7;public void show(){System.out.println(this.age+"..."+super.age);//子类可以直接访问父类非私有成员}}public class Test {public static void main(String[] args) {Student s=new Student();s.show();}}</span>
运行结果:7...3
2、成员函数:子类出现和父类一样的函数时,子类对象调用函数会运行子类函数内容覆盖父类函数内容(因此在定义新功能时可以使用覆盖,保留父类的功能定义并重写功能内容)
<span style="font-size:12px;">class Person{public void show(){System.out.println("person run...");}}class Student extends Person//Student继承Person类{public void show(){System.out.println("student run...");//子类重载父类的show方法}}public class Test {public static void main(String[] args) {Student s=new Student();s.show();//运行的是子类的重载后的show方法}}</span>
运行结果
PS.
在子类覆盖方法中,继续使用被覆盖的方法可以通过super.函数名获取
<span style="font-size:12px;">class Phone{ void call(){} void show(){ System.out.println("number" ); }}class NewPhone extends Phone{ void show(){ super.show(); //获取父类被重载的方法 System.out.println("name" ); System.out.println("pic" ); }}public class Test {public static void main(String[] args) {NewPhone p = new NewPhone(); p.show();}}</span>
PS.
a、子类覆盖父类,必须保证子类权限大于父类权限
b、父类的private方法不能被覆盖
b、重载(同一个类中):只看同名函数的参数列表 重写(子类中重写父类):子父类方法要一模一样
3、构造函数:在子类的对象进行初始化时,父类构造函数也会运行,因为子类的构造函数默认第一行隐示语句super(),而且子类中所有的构造函数默认第一行都是super()
<span style="font-size:12px;">class Fu{ Fu() { System.out.println("fu run...."); } }class Zi extends Fu{Zi() {//super();子类的第一行默认有一个访问父类构造函数的隐式语句System.out.println("zi run...."); } }public class Test {public static void main(String[] args) {Zi z = new Zi();}}</span>
运行结果:
那么为什么子类一定要访问父类的构造函数呢?
因为父类中的数据子类可以直接获取,所以子类对象建立时,需要先查看父类是如何对这些数据进行初始化的。
<span style="font-size:12px;">class Fu//父类没有空参数的构造函数</span><span style="font-size:12px;">{ Fu(int i) { System.out.println("fu run...."+i); } }class Zi extends Fu{Zi() { //super();子类的第一行默认有一个访问父类构造函数的隐式语句 //父类没有空参数的构造函数,因此此处要手动添加super(参数)来访问父类的指定构造函数 System.out.println("zi run...."); } }public class Test {public static void main(String[] args) {Zi z = new Zi();}}</span>
运行结果:
PS.
1、当父类中没有空参数的构造函数时,子类的构造函数必须通过this或者super语句指定要访问的构造函数。
2、子类构造函数中如果使用this调用了本类构造函数,那么默认的super();就没有了,因为super和this都只能定义在第一行,所以只能有一个。但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。
3、super语句必须要定义在子类构造函数的第一行!因为父类的初始化动作要先完成。
对象的实例化过程
<span style="font-size:12px;">class Fu{ Fu(){ super(); //调用的是子类的show方法,此时其成员变量num还未进行显示初始化 show(); return; } void show(){ System.out.println("fu show" ); }}class Zi extends Fu{ int num = 8; Zi(){ super(); //通过super初始化父类内容时,子类的成员变量并未显示初始化,等super()父类初始化完毕后,才进行子类的成员变量显示初始化 return; } void show(){ System.out.println("zi show..." + num); }}class Test{ public static void main(String[] args){ Zi z = new Zi(); z.show(); }}</span>
PS.
一个对象实例化过程,以Person p = new Person();为例:
1. JVM会读取指定的路径下的Person.class文件,并加载进内存,并会先加载Person的父类(如果有直接的父类的情况下)。
2. 在内存中开辟空间,并分配地址。
3. 并在对象空间中,对对象的属性进行默认初始化。
4. 调用对应的构造函数进行初始化。
5. 在构造函数中,第一行会先到调用父类中构造函数进行初始化。
6. 父类初始化完毕后,再对子类的属性进行显示初始化。
7. 再进行子类构造函数的特定初始化。
8. 初始化完毕后,将地址值赋值给引用变量。
【】final关键字:
1、修饰符,可以修饰类、函数、变量
2、被final修饰的类不可以被继承。(final class 类名)
3、被final修饰的方法不可以复写。(final 函数名)
4、可以修饰成员变量,也可以修饰局部变量,被final修饰的变量是一个常量只能被赋值一次
5、 写法规范:常量所有字母都大写,多个单词,中间用_连接。
【】抽象类:abstract(把多个事物的共性和本质的内容抽取出来)
Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。
抽象类特点:(和一般类无大区别,只是不确定部分需要子类明确)
1、抽象方法一定在抽象类中(格式:修饰符 abstract 返回值类型 函数名(参数列表) ;)
2、抽象方法和抽象类都必须被abstract关键字修饰
3、抽象类不可以用new创建对象,因为调用抽象方法没有意义
4、抽象类中的方法要被使用,必须由子类复写所有的抽象方法,建立子类对象调用(因此抽象类一定是父类)
PS.
抽象类和一般类的区别
A. 一般类有足够的信息描述事物。
抽象类描述事物的信息有可能不足。
B. 一般类中不能定义抽象方法,只能定义非抽象方法。
抽象类中可定义抽象方法,同时也可以定义非抽象方法。
C. 一般类可以被实例化。
抽象类不可以被实例化PS.
抽象类可以不用定义抽象方法,仅仅是不让该类创建对象
<span style="font-size:12px;">/** * 需求: 公司中程序员有姓名,工号,薪水,工作内容。 项目经理除了有姓名,工号,薪水,还有奖金,工作内容。 分析: 在这个问题领域中,通过名词提炼法: 程序员: 属性:姓名,工号,薪水。 行为:工作。 经理: 属性:姓名,工号,薪水,奖金。 行为:工作。 程序员和经理不存在着直接继承关系。 但是,程序员和经理却具有共性内容,可以进行抽取,因为他们都是公司的雇员。 可以将程序员和经理进行抽取,建立体系。 * */abstract class Employee{private String name,num; private int pay;Employee(String name,String num,int pay){this.name=name;this.num=num;this.pay=pay;}abstract void work();}class Programmer extends Employee{Programmer(String name,String num,int pay){super(name,num,pay);}void work(){ System.out.println("程序员工作。。。"); }}class Manager extends Employee{Manager(String name,String num,int pay){super(name,num,pay);}public void work(){System.out.println("经理工作。。。");}</span><span style="font-size:12px;">}</span>
【】接口:(ingterface 类名)
特殊的抽象类,当抽象类中的方法都是抽象的,那么该类可以通过接口的形式表示,其中的常量和修饰符有固定的修饰符
常量:public static fin
方法:public abstract
interface inter{}interface interA{}class demo{}class test extends demo implements inter,interA{}//多实现加继承,接口之间可以多继承。接口特点:
a、接口是对外暴露的规则
b、接口是程序的功能扩展
c、接口可以用来多实现
d、类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口
e、接口与接口之间可以有继承关系。(继承和接口近似于属于的基本功能和扩展的功能区别,继承是 is a接口是like a)
P.S.
a、虽然抽象类中的全局变量和抽象方法的修饰符都可以不用写,但是这样阅读性很差。所以,最好写上。
b、类与类之间是继承关系,类与接口直接是实现关系。
c、接口不可以实例化,能由实现了接口并覆盖了接口中所有的抽象方法的子类实例化。否则,这个子类就是一个抽象类。
<span style="font-size:12px;">interface CC{ void show();}interface MM{ void method();}//接口与接口之间是继承关系,而且接口可以多继承interface QQ extends CC,MM{ public void function();}class WW implements QQ{ //覆盖3个方法 public void show(){} public void method(){} public void function(){}} </span>
抽象类和接口的异同点?
相同点:
都是不断向上抽取而来的。
不同点:
a、 抽象类需要被继承,而且只能单继承。
接口需要被实现,而且可以多实现。
b、抽象类中可以定义抽象方法和非抽象方法,子类继承后,可以直接使用非抽象方法。
接口中只能定义抽象方法,必须由子类去实现。
c、 抽象类的继承,是is a关系,定义该体系的基本共性内容。接口的实现是like a关系。
3 多态
多态:事物存在的多种体现形态 animal c=new cat()//类型提升,向上转型>>>cat c=(cat)a//强制将父类的引用转成子类类型。
多态的体现:父类的引用指向了自己的子类对象,接受自己的子类对象(Animal a=new cat())
多态的前提:必须是类和类之间的关系,要么继承要么实现
好处:提高了代码的扩展性,前期定义的代码可以使用后期的内容。
弊端:前期定义的内容不能使用(调用)后期子类的特有内容。
<span style="font-size:12px;">abstract class Animal{ abstract void eat();}class Cat extends Animal{ void eat(){ System.out.println("猫吃鱼"); }void catchMouse(){System.out.println("猫抓老鼠");};}class Dog extends Animal{ void eat(){ System.out.println("狗吃骨头"); }void look(){System.out.println("狗看家");};}class Pig extends Animal{ void eat(){ System.out.println("猪吃菜"); }void sleep(){System.out.println("猪睡觉");};}class Test{public static void main(String[] args) {function(new Cat());function(new Dog());function(new Pig());}public static void function(Animal a){a.eat();}}</span>
运行结果:
<span style="font-size:12px;">abstract class Animal{ abstract void eat();}class Cat extends Animal{ void eat(){ System.out.println("猫吃鱼"); }void catchMouse(){System.out.println("猫抓老鼠");};}class Dog extends Animal{ void eat(){ System.out.println("狗吃骨头"); }void look(){System.out.println("狗看家");};}class Pig extends Animal{ void eat(){ System.out.println("猪吃菜"); }void sleep(){System.out.println("猪睡觉");};}class Test{public static void main(String[] args) {function(new Cat());function(new Dog());function(new Pig());}public static void function(Animal a){<span style="font-family:微软雅黑;">//Animal a=new Cat()父类的引用指向子类对象,向上转型</span>a.eat();<span style="font-family:微软雅黑;">//直接定义子类的特殊方法a.catchMouse会报错,因为Animal类中没有catchMouse方法</span>if(a instanceof Cat)<span style="font-family:微软雅黑;">//instanceof-关键字(对象是否属于指定的类型)</span>{Cat c=(Cat) a;<span style="font-family:微软雅黑;">//向下强转型,始终都是子类类型在做变化</span>c.catchMouse();<span style="font-family:微软雅黑;">//直接</span>}else if(a instanceof Dog){((Dog) a).look();}else if(a instanceof Pig){((Pig) a).sleep();}}}</span>
运行结果:
多态中成员变量的特点
编译时:参考引用型变量所属的类中是否有调用的成员变量。有,编译通过,没有,编译失败。
运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量。
简单说:编译和运行都参考等号的左边。
<span style="font-size:12px;">class Fu{ int num = 3;}class Zi extends Fu{ int num = 4;}class DuoTaiDemo{ public static void main(String[] args){ Zi f1 = new Zi(); System.out.println(f1.num);<span style="font-family:微软雅黑;">//调用的子类的成员变量</span> Fu f2 = new Zi(); System.out.println(f2.num);<span style="font-family:微软雅黑;">//调用的是父类的成员变量</span> } }</span>
运行结果:4 3
多态中成员函数的特点:(非静态)
编译时:参考引用型变量所属的类中是否有调用的函数。有,编译通过。没有,编译失败。
运行时:参考的是对象所属的类中是否有调用的函数。
简单说:编译看左边,运行看右边。
<span style="font-size:12px;">class Fu{ void show(){ System.out.println("fu show"); }}class Zi extends Fu{ void show(){ System.out.println("zi show"); }}class Test{public static void main(String[] args) {Fu c=new Zi();c.show();}}</span>
运行结果:
多态中成员函数的特点:(静态)
编译时:参考的是对象所属的类中是否有调用的函数。
运行时:参考的是对象所属的类中是否有调用的函数。
简单说:编译和运行看左边。
class Fu{ static void method(){ System.out.println("fu static method"); }}class Zi extends Fu{ static void method(){ System.out.println("zi static method"); }}class Test{public static void main(String[] args) {Fu c=new Zi();c.method();//这里调用的是父类的静态方法Fu.method();//静态方法是类方法,对象还没有时就已经存在于方法区}}
运行结果:
4 内部类
内部类:将一个类定义在另一个类的里面,里面那个类就称为内部类(内置类,嵌套类)
访问特点:
a、内部类可以直接访问外部类的成员(包括私有)
b、外部类访问内部类成员必须创建内部类对象
<span style="font-size:12px;">class Outer{ private int num = 3; class Inner { void show(){ System.out.println("Inner run..." + num); } }}class Test{ public static void main(String[] args){ //直接访问外部类中的内部类中的成员 Outer.Inner in = new Outer().new Inner(); in.show(); }}</span>
P.S.
1、内部类定义在成员位置上,可以被private、static成员修饰符修饰。被static修饰的内部类只能访问外部类中的静态成员。
2、静态的内部类,内部类成员也是静态的,可以不用创建内部类对象,直接调用。
<span style="font-size:12px;">class Outer{ private static int num = 3; static class Inner { static void show(){ System.out.println("Inner run..." + num); } }}class Test{ public static void main(String[] args){ //如果内部类是静态的,相当于一个外部类 Outer.Inner in = new Outer.Inner(); in.show(); Outer.Inner.show();//内部类为静态的可以直接通过类名访问 }}</span>
P.S.如果内部类中定义了静态成员,该内部类也必须是静态的!
<span style="font-size:12px;">class Outer{ int num = 3; class Inner{ int num = 4; void show(){ int num = 5; System.out.println(num); System.out.println(this.num); System.out.println(Outer.this.num); } } void method(){ new Inner().show(); }}class Test{ public static void main(String[] args){ new Outer().method(); }}</span>
运行结果 :5 4 3
内部类定义在局部位置上,也可以直接访问外部类中的成员;同时可以访问所在局部中的局部变量,但必须是被final修饰的。
<span style="font-size:12px;">class Outer{ int num = 3; void method(final int y){ final int x = 9; class Inner{ void show(){ System.out.println("show..." + x + "," + y); } } Inner in = new Inner(); in.show(); } }class Test{ public static void main(String[] args){ new Outer().method(4); }}</span>
【注意】内部类定义了静态变量,内部类必须是静态的。
【注意】静态是成员修饰符,不能修饰局部变量。
内部类定义在局部
1、不可以被成员修饰符修饰如:static
2、可以直接访问外部类中的成员,因为还持有外部类中的引用,但是不可以访问他所在的局部中的变量,只能访问被final修饰的局部变量
【】匿名内部类
内部类必须继承一个类或者实现接口
abstract class Demo//匿名内部类需要继承一个类或者实现接口{abstract void show();}class Outer{ int num = 3; /*class Inner extends Demo//一般定义内部类方法 { void show() { System.out.println("show....."+Outer.this.num); } }*/ void method(){ //new Inner().show() //匿名内部类,将内部类(注释掉的代码块)简写 new Demo() { void show() { System.out.println("show....."+Outer.this.num); } }.show(); }}class Test{ public static void main(String[] args){ new Outer().method(); }}内部类格式:new 父类或者接口(){定义子类的功能}------------(实质为一个匿名子类对象 ,因此上面的方法只能对方法也只能调用一次)
abstract class Demo//匿名内部类需要继承一个类或者实现接口{abstract void show1();abstract void show2();}class Outer{ int num = 3; /*class Inner extends Demo { void show() { System.out.println("show....."+Outer.this.num); } }*/ void method(){ //new Inner().show() //匿名内部类,将内部类(注释掉的代码块)简写 Demo d=new Demo()//当父类有多个方法时可以定义一个父类引用指向子类对象,实现多个方法调用 { void show1() { System.out.println("show.....1..."+Outer.this.num); } void show2() { System.out.println("show.....2..."+Outer.this.num); } void show3() { System.out.println("show.....3..."+Outer.this.num); } }; d.show1(); d.show2(); //d.show3();会报错,不能调用匿名对象的特有方法,因为父类中没有定义此方法无法调用 }}class Test{ public static void main(String[] args){ new Outer().method(); }}
运行结果
【例】
interface Inter//匿名内部类需要继承一个类或者实现接口{void method();}class Outer{ int num = 3; /*static class Inner implements Inter { public void method() { System.out.println("method run"); } }*/ public static Inter function() { //return new Inner(); return new Inter()//匿名内部类 { public void method() { System.out.println("method run"); } }; } }class Test{ public static void main(String[] args){ //Outer.function() 说明Outer中有一个静态方法是function //.method(); function的返回值是对象,而且是Inter类型的对象 Outer.function().method(); }}【例】
interface Inter{ void show1(); void show2();}/*通常的使用场景之一:当函数参数是接口类型时,而且接口中的方法不超过三个。可以用匿名内部类作为实际参数进行传递。*/class InnerClassDemo{ public static void main(String[] args){ show(new Inter(){ public void show1(){ System.out.println("...show1..." ); } public void show2(){ System.out.println("...show2..." ); } }); } public static void show(Inter in){ in.show1(); in.show2(); }}【例】
class Test{ public static void main(String[] args){ new Object()//创建Object的子类匿名对象 { void show() { System.out.println("object run"); } }.show(); }}
- 黑马程序员-java基础(四)-面向对象(封装、继承、多态)
- 黑马程序员<java基础<面向对象(封装,继承,多态,抽象)>>
- 黑马程序员----Java基础之面向对象(封装 继承 多态)
- 黑马程序员_毕向东JAVA基础_面向对象(封装&继承&多态)
- 黑马程序员——Java基础---深入理解面向对象(封装继承和多态)
- 黑马程序员学习日记 (四)面向对象三大特征: 封装 继承 多态
- 黑马程序员-面向对象(封装,继承,多态)
- 黑马程序员——java面向对象(封装、继承、多态)
- 黑马程序员——Java面向对象(二)之封装、继承、多态、接口等
- 黑马程序员---java面向对象 封装, 继承, 多态
- 黑马程序员---java基础之面向对象(一)三大特征(封装,继承,多态)
- 黑马程序员 JAVA基础<二> 面向对象之封装 继承 多态
- 黑马程序员----Java基础之面向对象(封装 继承 多态)(二)
- 黑马程序员——Java基础---面向对象(封装、继承、多态)
- 黑马程序员 JAVA基础 -面向对象(四)
- 黑马程序员-java基础-面向对象-继承
- Java基础之面向对象(封装、继承、多态)
- java基础<面向对象>总结(函数、封装、继承、多态)
- 后缀数组-解决字符串的利器
- 2015 ACM/ICPC 合肥赛区网络赛——吐槽向
- Python魔法方法指南
- 校门外的树
- hdu 5500 Reorder the Books
- 黑马程序员-java基础(四)-面向对象(封装、继承、多态)
- 斯坦福iOS7 2013-2014秋Assignment 6的一种答案 #8
- BufferReader 的使用
- 浅谈HTTP中Get与Post的区别
- 各大公司2016在线笔试(一)
- 最长公共子序列
- MAC电脑DNS劫持解决方法
- nginx文件类型错误解析漏洞
- ubuntu完美搭建git服务器-完善版