Java教程

Java基础知识复习2--面向对象篇

本文主要是介绍Java基础知识复习2--面向对象篇,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

所以内容均来自于b站“遇见狂神说”

构造器

一旦定义了一个有参构造,则必须显示的定义一个无参构造!!

package com.objectOriented.test1;
public class Student {
    String name;
    int age;
    public Student() {//有了有参构造必须定义一个无参的
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

mac中的构造快捷键是Command+n


小解对象内存分析

推荐原讲解视频:创建对象内存分析


三大特征之“封装”


三大特征之“继承”

mac的idea中查看继承关系的快捷键是ctrl+h

super

私有的东西无法被”直接继承“,既不能被直接访问但是可以间接的访问,比如上面通过上面的封装操作:一个方法在父类中是public修饰的,则可以在子类中直接调用;倘若是private修饰的,则不可以在子类中使用super关键字直接调用,应当通过父类中的getset方法既封装来操作!

调用父类的构造方法,必须放在子类构造器的第一行(既首先调用父类的构造方法),否则报错

public Class Person{
  public Person(){
    System.out.printLn("Person的无参构造执行了!")
  }
}
public Class Student extends Person{
  public Student(){
     //super(); //这个是隐藏的,默认的可以不写,倘若要写就一定要放在第一行!!!!
     System.out.printLn("Student的无参构造执行了!")
  }
}

强烈建议子类一定要把无参和有参的构造写一个出来


方法重写

注意,方法重写和方法重载是不一样的概念!!重写都是方法的重写,和属性无关!

重写关键字:Override

测试一:

public class A {
    public static void test(){//静态方法
        System.out.println("A->test");
    }
}
public class B extends A{
    public static void test(){//静态方法
        System.out.println("B->test");
    }
}
public class Application {
    public static void main(String[] args) {
        B b=new B();
        b.test();
        A a=new B();//父类的引用指向了子类
        a.test();
    }
}

执行结果是:

测试二:

public class A{
    public void test(){ //没有static修饰
        System.out.println("A->test");
    }
}
public class B extends A{
    @Override//重写 必须要有
    public void test() {//同上
        super.test();
    }
}
public class Application {
    public static void main(String[] args) {
        B b=new B();
        b.test();
        A a=new B();//父类的引用指向了子类
        a.test();
    }
}

执行结果:

为什么上面的差距这么大,借用弹幕的话:

因为静态方法是类的方法,而非静态类是对象的方法,有static时,a调用了A类的方法,因为a是用A类定义的;没有static时,A调用的是对象的方法,而a是用B类new的,既a是B类new出来的对象,因此调用了B的方法!

至于为什么可以这样写,这是多态的内容,重写就是为了多态而生!的!

 A a=new B();

另外,静态方法只能被继承,不能被重写

说到底,其本质是:a(地址)引用,指向了B类对象,所以调用的就是B类的方法


三大特征之多态(*******)

举个简单的例子,上面继承那一栏里面:

A a=new B();

既多态,父类引用子类对象!因为子类继承了父类的全部!!这样写是没有问题的!

测试一:

public class Person {
    public void run(){
        System.out.println("父类的run");
    }
}
public class Student extends Person{}
public class Application {
    public static void main(String[] args) {
        Student s1=new Student();
        Person p1=new Student();
        s1.run();
        p1.run();
    }
}

运行:

很好理解,父类和子类都有run方法,父类调用子类对象的方法,由于子类的run方法继承的是父类的没有改变,所以还是父类的run方法!

测试二:子类重写父类方法

public class Person {
    public void run(){
        System.out.println("父类的run");
    }
}
public class Student extends Person{
    @Override
    public void run() {
        System.out.println("子类的run");
    }
}
public class Application {
    public static void main(String[] args) {
        Student s1=new Student();
        Person p1=new Student();
        s1.run();
        p1.run();
    }
}

运行结果:

同上,父类调用子类的run方法,但是由于子类重写了run方法,所以执行的是子类重写后的run方法!

测试三:父类调用子类新增的方法

public class Person {
    public void run(){
        System.out.println("父类的run");
    }
}
public class Student extends Person{
    @Override
    public void run() {
        System.out.println("子类的run");
    }
    public void eat(){
        System.out.println("子类的eat");
    }    
}
public class Application {
    public static void main(String[] args) {
        Student s1=new Student();
        Person p1=new Student();
        s1.run();
        p1.eat();//一定会报错
    }
}

这个很好理解,因为父类没有该方法!能否执行看引用类型(左),执行内容看实际类型(右)

所以,假如是Person p1=new Student()这种,在与static无关的情况下,父类要运行的方法必须要是父子两个都有的!假如子类没有重写,则父类调用的还是父类本身的方法(子类继承的是父类的没变),子类重写了则调用的是子类重写的方法!

//Student能调用的方法都是自己的或者继承父类的
Student s1=new Student();
//父类型,可以指向之类,但是不能调用子类独有的方法
Person p1=new Student();

instanceof关键字

判断两个类之间是否存在父子关系

public class Person {
    public void run(){
        System.out.println("父类的run");
    }
}
public class Student extends Person{
    @Override
    public void run() {
        System.out.println("子类的run");
    }
}
public class Teacher extends Person{
    @Override
    public void run() {
        super.run();
    }
}
public class Application {
    public static void main(String[] args) {
        //Object->Person->Student
        //Object->Person->Teacher
        //Object->String
        Object object=new Student();
        System.out.println(object instanceof Student);
        System.out.println(object instanceof Person);
        System.out.println(object instanceof Object);
        System.out.println(object instanceof Teacher);
        System.out.println(object instanceof String);
    }
}

运行:

同理:

Person person=new Student();
System.out.println(person instanceof Student);
System.out.println(person instanceof Person);
System.out.println(person instanceof Object);
System.out.println(person instanceof Teacher);
//System.out.println(person instanceof String);

运行:

首先要明白一个规矩,既java遵循”编译看左(引用类型),执行看右(实际指向类型)“的规矩,所以最后一行代码报错,既首先编译就通不过,因为Person类和String是平级,没有父子关系!第4个是false是因为编译的时候看左(Person类)和Teacher有父子关系,可行!实际执行的时候看右(Student类)和 Teacher属于同级没有关系!

类型之间的转换:父与子

同基本数据类型一样,低转高自动转换,但是高转低就需要强制了!

public class Person {
    public void run(){
        System.out.println("父类的run");
    }
}
public class Student extends Person{
    @Override
    public void run() {
        System.out.println("子类的run");
    }
    public void go(){
        System.out.println("子类的独有的go方法");
    }
}

子转父:低转高,向上转型,直接转,丢失子类中原本可以直接调用的特有方法

Student s1=new Student();
s1.go();
Person p1=s1;
//p1.go();代码报错,因为没有go方法(既会丢失子类特有的方法)

父转子:高转低,向下转型,强制转,丢失父类被子类所重写掉的方法!

Person p2=new Student();
//p2不能使用Student独有的方法,如若使用强制转换
Student s1=(Student)p2;//高转低(右转左)需要强制转换
s1.go();
//或者
((Student)p2).go();

static关键字总结

用在方法上叫静态方法(也可以叫类方法,通过类名访问),用在属性上叫静态属性(如静态变量,也叫类变量)!

加了static关键字的,是从属于这个类的,别人用不了,只有本类能用!

public class Test1 {
    {
        //匿名代码块,赋初始值
        System.out.println("匿名代码块!");
    }
    static {
        //静态代码块,跟类一加载就执行,永久只执行一次!
        System.out.println("静态代码块!");
    }
    public Test1(){
        //构造器
        System.out.println("构造函数!");
    }
    public static void main(String[] args) {
        Test1 t1=new Test1();
        System.out.println("=============");
        Test1 t2=new Test1();
    }
}

运行:

同样的,一个类被final修饰了就不能被继承了,称之为断子绝孙修饰符


抽象类


接口(*********)

//interface 定义的关键字 接口都需要有实现类
public interface UserService {
    //接口中的属性默认都是静态常量,既public static final
    int AGE=10;
    //接口中的所有定义默认都是抽象的public,既定义的时候public abstract可以不用写
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}
public interface TimeService {
    void timer();
}
//类只能单继承,而接口可以多继承,且必须重新接口里面的方法
public class UserServiceImpl implements UserService,TimeService{
    @Override
    public void add(String name) {}
    @Override
    public void timer() {}
    @Override
    public void delete(String name) {}
    @Override
    public void update(String name) {}
    @Override
    public void query(String name) {}
}

总结:


内部类(面试爱问)

所谓内部类就是在一个类的内部再定义一个类,比如A类中定义一个B类,则B类称之为A类的内部类,A类称之为B类的外部类!

成员内部类

public class Outer {
    private int id;
    public void out(){
        System.out.println("这是外部类的方法");
    }
    public class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }
    }
}
public class Application {
    public static void main(String[] args) {
        Outer outer=new Outer();
        //内部类的创建格式
        Outer.Inner inner=outer.new Inner();
        inner.in();
    }
}

运行:

那么内部类能干嘛呢,我们通过内部类可以获得外部类的私有属性和方法

静态内部类

public class Outer {
    private int id;
    public void out(){
        System.out.println("这是外部类的方法");
    }
    public static class Inner{
        public void in(){
            System.out.println("这是内部类的方法");
        }
        public void getId(){
            //System.out.println(id);会报错
        }
    }
}

上面会报错的原因是因为:按照我们之前在static总结的来分析,类的执行(加载)顺序是静态->匿名->构造函数!所以,假如上面的的代码要想通过,得把id也用static修饰才可以!

局部内部类

public class Outer{
  //局部内部类
    public void method(){
        class Inner2{
            public void in(){}
        }
    }
}

需要说明的是,一个java文件里面只能有一个public class,但是却可以有多个class,既:

public class A{}
//public class A{} 错误
class C{}
class D{}
......

匿名内部类

public class test {
    public static void main(String[] args) {
        new Apple().eat();
    }
}
class Apple{
    public void eat(){
        System.out.println("吃了苹果");
    }
}

运行:

你甚至还可以在下面写上一个接口,当然这个就不做描述了!


异常

三种异常:

捕获和抛出异常

public class Exception1 {
    public static void main(String[] args) {
        int a=10;
        int b= 0;
        System.out.println(a/b);
    }
}

如何捕获这异常呢?-----------使用try/catch语句

public class Exception1 {
    public static void main(String[] args) {
        int a=10;
        int b= 0;
        try {//try表示监控区域(有问题转到catch)
            System.out.println(a/b);
        }catch (ArithmeticException e){//catch为捕获异常
            System.out.println("算术运行异常!");
        }finally {//处理善后工作
            System.out.println("over");
        }
        //finally可以不要,但是像涉及到IO,资源的关闭可以放到finally里!
    }
}

另外,try/catch也可以像if/else一样可以有多个catch:

public class Exception2 {
    public static void main(String[] args) {
        try {
            new Exception2().a();
        }catch (Error e){
            System.out.println("Error");
        }catch (Exception e){
            System.out.println("Exception");
        }catch (Throwable e){
            System.out.println("Throwable");
        }finally {
            System.out.println("over");
        }
    }
    public void a(){
         b();
    }
    public void b(){
        a();
    }
}

注意,异常等级越高的一定要放在后面!根据先后执行的顺序,满足了就不会执行后面的语句了!

不知道是什么异常可以这样写:

try{
  .....
}catch(Exception e){
  e.printStackTrace();//打印出具体的异常信息!
}

异常的抛出

public class Exception3 {
    public static void main(String[] args) {
        try{
            new Exception3().test(3,0);
        }catch (ArithmeticException e) {
            e.printStackTrace();
        }
    }
    //假设这个方法中处理不了这个异常,则可以主动抛出异常,让更高级别的去处理
    public void test(int a,int b){
        if(b==0){
            throw new ArithmeticException();
        } else{
            System.out.println(a/b);
        }
    }
}

自定义异常

//自定义一个异常类,要继承Exception
public class MyException extends Exception{
    private int detail;
    public MyException(int a){
        this.detail=a;
    }
    //toString:异常的打印信息
    @Override
    public String toString() {
        return "MyException{"+detail+"}";
    }
}
public class Test {
    //可能会存在异常的方法
    static void test(int a) throws MyException {//注意,这里是throws不是throw
        System.out.println("传递的参数为:"+a);
        if(a>10){
            throw new MyException(a);//处理为要么这里try/catch,要么抛出去
        }
        System.out.println("OK");
    }
    public static void main(String[] args) {
        try {
            test(11);
        }catch (MyException e){
            //e.printStackTrace();
            System.out.println("MyException>>"+e);//e即为执行toString()
        }
    }
}

异常在实际应用中的经验总结

这篇关于Java基础知识复习2--面向对象篇的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!