第五章 Java面向对象进阶

5.1.1 l类的继承

注意点

  • 关键字 extends
  • Java只有单继承(c++有多)
  • 父类又称 超类、基类、派生等
  • 子类可以继承父类所有的属性和方法(父类 的构造方法除外)
    但不一定都可以直接调用(父类私有属性方法private修饰)
  • 定义一个类时,没有调用extends,则它的父类是:java.lang.Object。
public class Test{
   public static void main(String[] args) {
       Student s = new Student("高淇",172,"Java");
       s.rest();
       s.study();
   }
}
class Person {
   String name;
   int height;
   public void rest(){
       System.out.println("休息一会!");
   }  
}
class Student extends Person {
   String major; //专业
   public void study(){
       System.out.println("在尚学堂,学习Java");
   }  
   public Student(String name,int height,String major) {
       //天然拥有父类的属性
       this.name = name;
       this.height = height;
       this.major = major;
   }
}

5.1.2 instanceof 运算符

  • instanceof是二元运算符,左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true;否则,返回false。比如:
public class Test{
    public static void main(String[] args) {
        Student s = new Student("高淇",172,"Java");
        System.out.println(s instanceof Person);
        System.out.println(s instanceof Student);
    }
}

PS:查看类的继承结构 Ctrl + T

5.1.4方法的重写override

就是在子类中写一个和父类方法名一样的 方法 调用子类此方法的时候用的是子类的…

注意点

  • “==”: 方法名、形参列表相同。

  • “≤”:返回值类型和声明异常类型,子类小于等于父类。

  • “≥”: 访问权限,子类大于等于父类。

5.2.1 Object类基本特性

  • Object类是Java的根基类,所Java都拥有它的属性和方法 如果在类的声明中没有使用extends继承父类
    则默认继承Object类

5.2.2 toString方法

class Person {
    String name;
    int age;
    @Override
    public String toString() {
        return name+",年龄:"+age;
    }
}
public class Test {
    public static void main(String[] args) {
        Person p=new Person();
        p.age=20;
        p.name="李东";
        System.out.println("info:"+p);
         
        Test t = new Test();
        System.out.println(t);
    }
}

5.2.3 ==和equals方法

  • “==” : 代表比较双方是否相同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等即是同一个对象。
  • " equals": 表示两个对象内容是否相同
public class Test {
	public static void main(String[] args) {
        Person p1 = new Person(123,"高淇");
        Person p2 = new Person(123,"高小七");     
        System.out.println(p1==p2);     //false,不是同一个对象
        System.out.println(p1.equals(p2));  //true,id相同则认为两个对象内容相同
        String s1 = new String("尚学堂");
        String s2 = new String("尚学堂");
        System.out.println(s1==s1);         //false, 两个字符串是同一个对象
        System.out.println(s1.equals(s2));  //true,  两个字符串内容相同
    }
}
class Person {
    int id;
    String name;
    public Person(int id,String name) {
        this.id=id;
        this.name=name;
    }/*结果
false
false
true
true
*/

5.3 super关键字

  • super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
  • 每一个继承父类的子类默认都会调用一下 super() 父类无参的构造方法;
    当加上super.父类中方法名时调用的是所继承的父类的方法
public class TestSuper01 { 
    public static void main(String[] args) {
        new ChildClass().f();
    }
}
class FatherClass {
    public int value;
    public void f(){
        value = 100;
        System.out.println ("FatherClass.value="+value);
    }
}
class ChildClass extends FatherClass {
    public int value;
    public void f() {
        super.f();  //调用父类对象的普通方法
        value = 200;
        System.out.println("ChildClass.value="+value);
        System.out.println(value);
        System.out.println(super.value); //调用父类对象的成员变量
    }
}

5.4.2 封装的实现—使用访问控制符

修饰符范围限制

在这里插入图片描述

  • private 只能在同一个类中
  • default(缺省的修饰符 )同一个包中都可以
  • protected 不同包中的子类也可以(同一包下可以)
  • public 所有包中的,所有类都可以

5.4.3 封装的使用细节

封装就是将一个对象的属性和操作进行整合处理
简单点说就是利用一个函数 用户只能通过这个 函数进行 操作

  • 封装可以实现 数据 可控
  • 可以减少后期 代码更改的工作量
     再比如说,如果哪天我们需要将Person类中的age属性修改为String类型的,
     你会怎么办?你只有一处使用了这个类的话那还比较幸运,但如果你有几十
     处甚至上百处都用到了,那你岂不是要改到崩溃。而封装恰恰能解决这样的
     问题。如果使用封装,我们只需要稍微修改下Person类的setAge()方法即可,
     而无需修改使用了该类的客户代码。

5.4.3 封装的使用细节

  • 目前我们一般用 private 修饰属性(进可以自身类内调用)
  • 对于属性 使用get/set 方法进行封装(public)
  • boolean 类型的属性 get 要用 is
  • 一些用于本类中的辅助放方法用 private 修饰 用于他类的 用public

public class Person {
    // 属性一般使用private修饰
    private String name;
    private int age;
    private boolean flag;
    // 为属性提供public修饰的set/get方法
    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 boolean isFlag() {// 注意:boolean类型的属性get方法是is开头的
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

5.5 多态(polymorphism)

前提条件

  • 多态是方法的多态,不是属性的多态(多态与属性无关)。
  • 多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。
  • 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。

就是 写一个 用父类的方法 从中会自动选择 哪一个类型
个人理解:感觉就是 开了一个引用父类类型的 方法 从而 对这个方法进行调用是 由于 其子类(dog/cat)都
继承于 父类所以 会形成 父类方法的重载 其 中(dog/cat/animal)作为 不同类型的参数

class Animal {
    public void shout() {
        System.out.println("叫了一声!");
    }
}
class Dog extends Animal {
    public void shout() {
        System.out.println("旺旺旺!");
    }
    public void seeDoor() {
        System.out.println("看门中....");
    }
}
class Cat extends Animal {
    public void shout() {
        System.out.println("喵喵喵喵!");
    }
}
public class TestPolym {
    public static void main(String[] args) {
        Animal a1 = new Cat(); // 向上可以自动转型
        //传的具体是哪一个类就调用哪一个类的方法。大大提高了程序的可扩展性。
        animalCry(a1);
        Animal a2 = new Dog();
        animalCry(a2);//a2为编译类型,Dog对象才是运行时类型。
         
        //编写程序时,如果想调用运行时类型的方法,只能进行强制类型转换。
        // 否则通不过编译器的检查。
        Dog dog = (Dog)a2;//向下需要强制类型转换
        dog.seeDoor();
    }
 
    // 有了多态,只需要让增加的这个类继承Animal类就可以了。
    static void animalCry(Animal a) {
        a.shout();
    }
 
    /* 如果没有多态,我们这里需要写很多重载的方法。
     * 每增加一种动物,就需要重载一种动物的喊叫方法。非常麻烦。
    static void animalCry(Dog d) {
        d.shout();
    }
    static void animalCry(Cat c) {
        c.shout();
    }*/
}

5.7 final关键字

  1. 修饰变量: 被他修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。final int MAX_SPEED = 120;
  2. 修饰方法:该方法不可被子类重写。但是可以被重载! final void study(){}
  3. 修饰类: 修饰的类不能被继承。比如:Math、String等。

5.8 抽象方法和抽象类(abstract)

** 使用abstract修饰的方法,没有方法体,只有声明。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。**

  • 有抽象方法的类 必须定义成抽象类
  • 抽象类不能被具体化(即不能用new来创建) 只能被子类调用
  • 抽象类只能被继承
  • 抽象方法必须被 子类实现
  1. (抽象类中只有抽象方法的声明,抽象方法写在继承他的子类中(非抽象),
  2. 子类中必须写抽象方法否则报错)
  3. 可以new子类因为只是继承而非 abstract类
package _01_java入门阶段;
public class Test {
	//测试抽象类
	    public static void main(String[] args) {
	        Dog a = new Dog();
	        a.shout();
	        a.seeDoor();
	    }
}
abstract class Animal {
    abstract public void shout();  //抽象方法
}
class Dog extends Animal { 
    //子类必须实现父类的抽象方法,否则编译错误
    public void shout() {
        System.out.println("汪汪汪!");
    }
    public void seeDoor(){
        System.out.println("看门中....");
    }
}
class Cat extends Animal{
	public void shout() {
		System.out.println("喵喵~");
	}
}

5.9.2 如何定义和使用接口? (interface)

声明格式: interface 同类同级

[访问修饰符]  interface 接口名   [extends  父接口1,父接口2…]  {
常量定义;  
方法定义;
}
  1. 访问修饰符:只能是public或默认。
  2. 接口名:和类名采用相同命名机制。
  3. extends:接口可以多继承。
  4. 常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是。
  5. 方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。
    几个特性
  6. 子类通过implements来实现接口中的规范。
  7. 接口不能创建实例,但是可用于声明引用变量类型。
  8. 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的。
  9. JDK1.7之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。
  10. JDK1.8后,接口中包含普通的静态方法。
public class TestInterface {
    public static void main(String[] args) {
        Volant volant = new Angel();//不能调用 Angel中的 helpOther();
        //Angel volant= new Angel(); //就可以调用 helpOther();
        volant.fly();
        System.out.println(Volant.FLY_HIGHT);
         
        Honest honest = new GoodMan();
        honest.helpOther();
    }
}
/**飞行接口*/
interface Volant { 
    int FLY_HIGHT = 100;  // 总是:public static final类型的;
    void fly();   //总是:public abstract void fly();
}
/**善良接口*/
interface Honest { 
    void helpOther();
}
/**Angle类实现飞行接口和善良接口*/
class Angel implements Volant, Honest{
    public void fly() {
        System.out.println("我是天使,飞起来啦!");
    }
    public void helpOther() {
        System.out.println("扶老奶奶过马路!");
    }
}
class GoodMan implements Honest {
   public void helpOther() {
        System.out.println("扶老奶奶过马路!");
    }  
}
class BirdMan implements Volant {
    public void fly() {
        System.out.println("我是鸟人,正在飞!");
    }
}

5.9.3 接口的多继承

interface A {
    void testa();
}
interface B {
    void testb();
}
/**接口可以多继承:接口C继承接口A和B*/
interface C extends A, B {
    void testc();
}
public class Test implements C {
    public void testc() {
    }
    public void testa() {
    }
    public void testb() {
    }
}

5.10.2内部类的分类

  • 成员内部类(非静态 、 静态)
  • 匿名内部类
  • 局部内部类

非静态成员内部类

  1. 非静态成员内部类必须定义外部类的对象里
  2. 非静态内部类可以直接访问 外部类成员,但是外部不能直接访问内部
  3. 非静态成员内部类不能定义 静态属性方法初始化块等
  4. 静态外部类静态方法、代码块不能访问非静态内部类也不能使用它定义变量、创建实例

成员变量访问要点:
5. 内部类里方法的局部变量:变量名。
6. 内部类属性:this.变量名。
7. 外部类属性:外部类名.this.变量名。
1.外部类中定义内部类:
new Inner()
2.外部类以外的地方使用非静态内部类:
Outer.Inner varname = new Outer().new Inner()

package _01_java入门阶段;
public class Test {
	    public static void main(String[] args) {
	        //先创建外部类实例,然后使用该外部类实例创建内部类实例
	        Outer.Inner inner =new Outer().new Inner();
	        inner.show();//一起创建
	   
	        Outer outer = new Outer();//分步创建
	        Outer.Inner inn = outer.new Inner();
	        inn.show();
	    }
}
class Outer {
    private int age = 10;
    class Inner {
        int age = 20;
        public void show() {
            int age = 30;
            System.out.println("内部类方法里的局部变量age:" + age);// 30
            System.out.println("内部类的成员变量age:" + this.age);// 20
            System.out.println("外部类的成员变量age:" + Outer.this.age);// 10
        }
    }
}

静态内部类*

  1. 当一个静态内部类对象存在,并不一定存在对应的外部类对象。 因此,静态内部类的实例方法不能直接访问外部类的实例方法。
  2. 静态内部类看做外部类的一个静态成员。 因此,外部类的方法中可以通过:“静态内部类.名字”的方式访问静态内部类的静态成员,通过 new 静态内部类()访问静态内部类的实例。
class Outer{
    //相当于外部类的一个静态成员
    static class Inner{
    }
}
public class TestStaticInnerClass {
    public static void main(String[] args) {
        //通过 new 外部类名.内部类名() 来创建内部类对象
        Outer.Inner inner =new Outer.Inner();
    }
}

匿名内部类

适合那种只需要使用一次的类。比如:键盘监听操作等等。

new  父类构造器(实参类表) \实现接口 () {
           //匿名内部类类体!
}
this.addWindowListener(new WindowAdapter(){
        @Override
        public void windowClosing(WindowEvent e) {
            System.exit(0);
        }
    }
);
this.addKeyListener(new KeyAdapter(){
        @Override
        public void keyPressed(KeyEvent e) {
            myTank.keyPressed(e);
        }      
        @Override
        public void keyReleased(KeyEvent e) {
            myTank.keyReleased(e);
        }
    }
);

局部内部类

定义在方法内部的,作用域只限于本方法

public class Test2 {
    public void show() {
        //作用域仅限于该方法
        class Inner {
            public void fun() {
                System.out.println("helloworld");
            }
        }
        new Inner().fun();
    }
    public static void main(String[] args) {
        new Test2().show();
    }
}

5.11.3阅读API文档

5.11.4 String类常用的方法

在这里插入图片描述

String类常用方法实例

public class StringTest1 {
    public static void main(String[] args) {
        String s1 = "core Java";
        String s2 = "Core Java";
        System.out.println(s1.charAt(3));//提取下标为3的字符
        System.out.println(s2.length());//字符串的长度
        System.out.println(s1.equals(s2));//比较两个字符串是否相等
        System.out.println(s1.equalsIgnoreCase(s2));//比较两个字符串(忽略大小写)
        System.out.println(s1.indexOf("Java"));//字符串s1中是否包含Java
        System.out.println(s1.indexOf("apple"));//字符串s1中是否包含apple
        String s = s1.replace(' ', '&');//将s1中的空格替换成&
        System.out.println("result is :" + s);
        
    }
}
public class StringTest2 {
    public static void main(String[] args) {
        String s = "";
        String s1 = "How are you?";
        System.out.println(s1.startsWith("How"));//是否以How开头
        System.out.println(s1.endsWith("you"));//是否以you结尾
        s = s1.substring(4);//提取子字符串:从下标为4的开始到字符串结尾为止
        System.out.println(s);
        s = s1.substring(4, 7);//提取子字符串:下标[4, 7) 不包括7
        System.out.println(s);
        s = s1.toLowerCase();//转小写
        System.out.println(s);
        s = s1.toUpperCase();//转大写
        System.out.println(s);
        String s2 = "  How old are you!! ";
        s = s2.trim();//去除字符串首尾的空格。注意:中间的空格不能去除
        System.out.println(s);
        System.out.println(s2);//因为String是不可变字符串,所以s2不变
    }
}

xxx

课后部分习题

2.以下关于继承条件下构造方法执行过程的代码的执行结果是( )。(选择一项)

class Person {   
    public Person() {
        System.out.println("execute Person()");
    }
}
class Student extends Person { 
    public Student() {       
        System.out.println("execute Student() ");
    }  
}
class PostGraduate extends Student {   
    public PostGraduate() {  
        System.out.println("execute PostGraduate()");
    }  
}
public class TestInherit {
    public static void main(String[] args) {
        new PostGraduate();       
    }
}

A.execute Person()
execute Student()
execute PostGraduate()

B.execute PostGraduate()

C.execute PostGraduate()
execute Student()
execute Person()

D.没有结果输出
//所有子类会先用super()方法调用父类构造方法,再调用自己的构造方法
3.编译运行如下Java代码,输出结果是( )。(选择一项)

class Base {
    public void method(){
        System.out.print ("Base method");
    }
}
class Child extends Base{   
    public void methodB(){
        System.out.print ("Child methodB");
    }
}
class Sample {
    public static void main(String[] args) {
        Base base= new Child();
        base.methodB();
    }
}

A.Base method

B.Child methodB

C.hild methodB

D.编译错误
//上转型对象无法使用对象的新增方法,只能使用继承或重写的方法

4.在Java中关于abstract关键字,以下说法正确的是( )。

A.abstract类中可以没有抽象方法

B.abstract类的子类也可以是抽象类

C.abstract方法可以有方法体

D.abstract类可以创建对象

A.abstract类可以有abstract方法,也可以有非abstrct方法
B:非abstract类为abstract类的子类的话,必须重写父类方法,如果子类也是abstract类的话,可以继承或重写abstra方法
D:abstract类不能new对象,但可以成为子类的上转型对象,此时该对象可以调用子类的重写方法
————————————————
版权声明:本文为CSDN博主「流雪扶风」的原创文章截取,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_34834846/article/details/81412804

5.在Java接口中,下列选项中属于有效的方法声明是( )。(选择二项)

A.public void aMethod( );

B.final void aMethod( );

C.void aMethod();

D.private void aMethod( );

B:final可以修饰接口变量,但不能修饰接口方法,因为接口的方法是是抽象方法,必须通过子类继承重写来实现
D:接口的方法一定是public的,以在其他类中实现
发布了55 篇原创文章 · 获赞 1 · 访问量 964

猜你喜欢

转载自blog.csdn.net/weixin_43556527/article/details/103352357