所以内容均来自于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
私有的东西无法被”直接继承“,既不能被直接访问但是可以间接的访问,比如上面通过上面的封装操作:一个方法在父类中是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();
判断两个类之间是否存在父子关系
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关键字的,是从属于这个类的,别人用不了,只有本类能用!
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() } } }