面向对象的三大特征继承、封装、多态,最编写具有面向对象思想的Java程序。
认识Java中的面向对象的思想,掌握面向对象的基本原则以及基本实现原理。 面向对象思想开发的程序的优势:稳定性、可扩展性、可重用性 java语言实现面向对象的三大特征:继承、封装、多态; 1.什么是对象?万物皆对象;对象是类的实例表现;对象是特定类型的数据(计算机世界只有数据) 2.什么是面向对象?人关注对象即人关注事物信息(对计算机而言) 3.什么是类?类是模子,确定对象将会拥有的特性(属性)和行为(方法);类是对象的类型 4.类和对象的关系: 类是模子,确定对象将会拥有的特性(属性)和行为(方法) 对象是类的实例表现 类是对象的类型 对象是特定类型的数据(计算机世界只有数据) 类-抽象的概念-模板 对象-一个看得到、摸得着的具体实体 同一个类的所有对象都拥有相同的特征和行为,类规定了对象拥有的特征和行为,对象是具有属性和行为的实体 “类”—实例化—”对象” 属性和方法: 属性:对象具有的各种静态特征(“对象有什么”).方法:对象具有的各种动态行为(“对象能做什么”) 面向对象程序编程:类—实例化对象—完成具体的程序 JAVA中通过包管理类(就像操作系统中通过不同文件夹管理不同的文件) 包的命名规范:1.英文字母小写2.域名的倒序+模块名+功能名 在Java中,目标类和当前类位于同一包下,是不需要导入的 一个.java文件内可以有多个类,但只能有一个public类,且此类名与文件名大小写一致。.java文件中可不含public类,若只有一个非public类,可与文件名不同。 类中直接定义的属性和方法是成员属性和成员方法,类中的成员方法中定义的属性(一般称变量)是局部变量。 类中的成员属性都有默认值,局部变量没有默认值(String类型的为:null,int 类型的为:0,double 类型的为:0.0),对象名.方法名()和对象名.属性名分别调用对象中对应的方法和属性。 单一职责(功能)原则(面向对象的程序设计五大基本原则之一):一个类有且只有一个引起功能变化的原因(一个类最好只有一个功能)。若在一个类中,承担的功能(职责)越多,那么这个类的交融、耦合性越高(连锁反应:这个交融/耦合性高的类中一个功能若发生变化可能引起同类其他功能发生连锁变化,进而影响整个程序的运行),被复用的可能性越低。在程序设计中,尽量把不同的职责,放在不同的类中(也就是说把不同的可能引发变化的原因封装到不同的类里面,这样当一方发生变化时,对其他参与者的影响会少很多,并提升复用性) 对象实例化:实例化对象的过程可分为两部分:1.声明对象(对象类型 对象名).在内存的栈存储空间中开辟一个空间声明一个对象名。空间的值是null(空)。eg:Cat one;并不能通过对象名调用方法或属性。 2.实例化对象 new关键字 类名()。在内存的堆存储空间中开辟一个创建的对象的空间,对应一个具体的地址。eg:new Cat(); 声明对象和实例化对象通过赋值运算符”=”连接,将栈中的声明的对象指向堆实例化的具体空间。也就是栈中空间存储的是堆中空间的地址(地址引用/对象引用)。Cat one=new Cat(); 同一个类的所有对象都拥有相同的特征和行为。 通过new关键字开辟不同空间,不同对象指向不同地址,所以修改一个对象的信息不会对其他对象产生影响的。
第二种对象实例化方式:Cat two=one; 不同对象指向同一地址,所以修改一个对象的信息对其他对象产生影响。 Ctrl+/单/多行注释快捷键 堆和栈都属于内存区,堆空间存的是对象,存放所有new出来的对象;栈中存的是基本数据类型和堆中对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象),栈空间用于存储程序运行时在方法中声明的所有的局部变量;方法区用于存放类的信息(包括方法) 构造方法(又叫构造函数、构造器,是new关键字的好搭档),不能被对象单独调用。语句格式:访问修饰符(public)(没有返回类型)构造方法名(可指定参数){//初始化代码}。注:1.构造方法与类同名且没有返回值 2.只能在对象实例化的时候调用(是new关键字的好搭档,配合new关键字调用)3.当没有指定构造方法时,系统会自动添加无参构造方法4.当有指定构造方法,无论是有参、无参的构造方法,都不会自动添加无参的构造方法5.一个类中可以有多个构造方法 所以**实际对象实例化的语句格式是:类名 对象名=new 构造方法名();**而不是之前的:类名 对象名=new 类名();之前定义格式更多是便于使用更好地记忆为后面深入理解原理作铺垫。 普通方法也可以和类名相同(不建议),但是一定要有返回类型或者void,不然就变成构造方法了。 **构造方法用来定义对象,普通方法通过对象调用。构造方法一般用于创建类的实例并可对实例的成员变量进行初始化;而成员方法实现对类中成员变量的操作,完成各种逻辑操作。**构造方法中没有void关键字,若在构造方法前加void,这个构造方法就变成了成员方法,也无法进行实例化了。 在Java中,一个对象在可以被使用之前必须要被正确地初始化。在实例化一个对象时,JVM首先会检查相关类型是否已经加载并初始化1、通过调用构造方法是实例化一个对象! 2、类的定义完成并首次在JVM中加载是类的初始化!eg:在完成Cat类的定义后,首次new Cat()对象会在JVM中完成Cat类的初始化,然后实例化一个Cat类对象叫one!当第二次调用构造方法完成Cat类对象的实例化叫two时,直接调用构造方法实例化就可以了. 就近原则:程序开发中,当方法内外都有相同的属性名,在方法内对这个属性赋值,系统会优先就近原则对方法内的这个属性赋值,而方法外相同属性名的值不变。只有找不到才会扩大范围找。 this关键字:代表当前对象(当前对象的默认引用,谁调用了它谁就是当前对象),this.属性名可以解决当方法内外都有相同的属性名直接对对象的成员属性赋值,不再遵循就近原则。this不仅可以区分调用当前对象的属性还能区分调用当前对象的方法。 **一般this的使用是在构造方法中,在构造方法中这个类的对象还没有初始化,针对这个对象的属性和方法就无法直接通过对象名.属性名来区分重名情况。**若在普通方法中,如果要调用其他方法,是可以通过对象名.方法名来调用。但还是建议使用this。 同一个类中,普通的成员方法和构造方法可以不用this直接调用其他普通成员方法,构造方法之间用this(有无参数根据调用的构造方法)调用,构造方法不能被普通成员方法调用。在构造方法中调用父类或本类其他的构造方法只能写在有效代码行的第一句,写在第二句的就是语法错误(一个构造方法内只能调用一次构造方法)。 总结:面向对象程序设计:关注现实存在的事物的各方面的信息,从对象的角度出发,根据事物的特征进行程序设计。对象:用来描述客观事物的一个实体。类:具有相同属性和方法的一组对象的集合。 定义类: 语法: 类定义后,创建并引用对象: 语法: 成员属性有默认值,局部属性(局部变量)没有默认值,使用前需要赋值。 成员属性的初始值:基本类型(默认值):byte(0),short(0),int(0),long(0L),float(0.0f),double(0.0d),char(‘\u0000’),boolean(false).引用类型对象的初始值null。 return语句用在方法中有两个作用:1.是返回方法指定类型的值(这个值总是确定的).2.是结束方法的执行(仅仅一个return语句)。
什么是封装,以及如何在Java中实现封装。 面向对象的三大特征:封装、继承、多态。 封装:隐藏对象的信息(将类的某些信息隐藏在类内部,不允许外部程序(类外的程序)直接访问),留出访问的接口(通过该类提供的方法来实现对隐藏信息的操作和访问)。 特点:1.只能通过规定的方法访问数据2.隐藏类的实例细节,方便修改和实现 封装的意义:1.防止使用者错误修改系统的属性2.提高系统的独立性3.提高软件的可重用性 封装的代码实现: (private是私有的修饰符,表示只能在本类中访问这个属性或方法,public表示公开的,public修饰的属性和方法,在其他类中也能直接访问。 set/get方法的快捷生成:程序空白处鼠标右键-Source-Generate Getters and Setters… 条件限制既可以在set方法中又可以在get方法中,在set方法中作条件限制,是限制输入数据的应用场景。在get方法中作条件限制,是限制获取数据的应用场景。 封装可以避免逻辑错误(不是语法错误,编译不报错)对属性值的合法性进行控制. ). 使用包进行类管理(管理java文件,解决同名文件冲突(同名.java文件可以放在不同包中),如同操作系统中通过文件夹管理文件) Java中一个包里不能存在同名类,包的定义必须放在Java源文件中的第一行(语法:package 包名;),一个Java源文件中只能有一个package语句,包名全部英文小写,建议每个包内存储信息功能单一。 包的命名规范:1.域名全部小写2.域名倒序+模块名+功能名 调用同一工程下不同包中的类:1.加载不同包中的异名类(1.import 包名.;加载这个包中的所有类 2(建议这种,工作量小,提高效率).import 包名.指定的类名;加载这个包中的指定类3.可以在程序中作为参数列表或实例化对象时通过包名.类名直接加载.eg:包名.类名 对象名;或 包名.类名 对象名=new 包名.构造方法();)2.加载不同包中的同名类,在调用一个类时先执行加载效率高的类,加载效率低的类需要写全包名。或都需要写全包名. 加载类的顺序跟import导入语句的位置无关,**import 包名.;只能访问指定包名下的类,无法访问子包下的类**(eg:完整包名是com.imooc.a.b,加载的是import com.imooc.a;此时不能加载子包b中的类,只能加载a中的类)。
static关键字:静态信息,修饰的成员是静态成员(也叫类成员),静态属性/类属性(static+属性),静态方法/类方法(static+方法),static不能修饰方法中的局部变量和类,静态方法中不能直接访问同一个类中的非静态成员,只能直接调用同一个类中的静态成员.只能间接通过对象实例化后,对象.成员的方式访问同一个类中的非静态成员。静态方法中不能使用this(因为this是与实例相关). 静态成员特征:1.类对象共享(静态成员的内存空间对类的所有对象都是一样的)2.类加载时产生,销毁时释放,生命周期长(因为静态成员在这个类出现时,就分配空间存在,其内存空间对类的所有对象都是一样的,所以直到类的所有对象都销毁时,静态成员才销毁,而普通成员在这个类实例化对象后才会出现,其内容空间只与类的某个对象相关,随这个对象一起销毁)。 静态成员(全局成员)访问方式:1对象.成员(使用这种方式编译器会警告,但不会报错) 2.类.成员 静态方法和普通成员方法除调用方式的区别,还有不同:1、静态方法只能直接访问静态成员,普通成员方法可以直接访问静态成员(属性、方法)和普通成员(属性、方法)!2、静态方法在初始化类时初始化,并分配内存;普通方法只有先创建类的实例对象后,才能调用普通方法!3、静态方法在程序初始化后会一直贮存在内存中,不会被垃圾回收器回收! 非静态方法只在该类初始化后表示一个对象贮存在内存中,当该类的这个对象调用完毕后会被垃圾回收器收集释放。 普通代码块:方法{}中{}中的代码,顺序执行,先出现先执行 构造代码块:类{}中{}中的代码,创建对象时调用,优先于构造方法执行,多个构造代码块顺序执行,产生多少类实例,构造代码块执行多少次。可以直接对当前类中成员属性/静态属性赋值。构造代码块给所有的对象进行初始化,也就是说,所有的对象都会调用一个代码块,构造方法具有针对性(不同对象方法参数可能不一样) 静态代码块:类{}中static{}中的代码,类加载时调用,优先于构造代码块执行,多个静态代码块顺序执行,无论产生多少类实例,静态代码块只执行一次。仅希望执行一次的代码可以放在静态代码块中。可以直接对当前类中静态属性赋值(不能声明静态属性,可以调用静态属性),不能直接对非静态属性赋值。 程序运行过程:静态代码块-主方法-(其他语句)-构造代码块-构造方法-(其他语句)
学习封装在面向对象中的应用。 直接声明在类体中的变量(成员属性),Java会自动帮你初始化 ,如果是引用型,则初始化为null值。 如果变量是定义在方法内部,叫局部变量没有初始值 Ctrl+Shift+f快捷键调整表现格式 关联学生类和专业类信息:1(容易理解,参数列表长).在方法中添加两个参数,分别表示专业名称和学制年限2(更加简单,获取参数方便).在方法中添加1个专业对象作为参数,通过其属性获得相关信息3(关联性更强).在学生类中添加专业对象作为属性,通过其属性获得相关信息。 在Student类定义后,Student[] myStudents,表示数组对象还没有被创建,只是声明了一个Student数组对象引用,则默认值为null,没有指向任何对象的引用,运行会出现空指针异常。若Student[] myStudents=new Students[100];表示声明了一个Student数组对象并指向一个有100个Student数组对象的对象引用,创建数组对象后,因为数组元素类型是Student,也就是引用数据类型,因此每一个数组元素的值都为null。 在方法中通过对象作为参数,传递的是它的引用,可以通过引用获取该对象所有信息。 对象调用避免出现空指针异常:1.在定义对象/数组对象时同时初始化对象/数组对象2.只定义对象/数组对象,在调用对象的信息时再初始化对象/数组对象。
继承的特点,如何在Java中实现继承。 特点:1.利于代码复用2.缩短开发周期 继承(关键字extends):1.一种类与类之间的关系。2.使用已存在的类(父类或基类或超类,父类不能访问子类特有成员)的定义作为基础建立新类(子类或派生类,只能继承一个父类,子类可以访问父类的非私有成员,private私有成员不会被继承)。3.新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。 继承的关系:满足”A is a B”的关系就可以形成继承关系。 Windows+shift+O加载指定的类 子类继承了父类的方法,可以对继承的方法进行重写或者重载 方法重写(有继承关系的子类中,子类重写父类的方法(覆盖)):语法规则:返回值类型、方法名、参数类型/顺序/个数都要与父类继承的方法相同。方法的访问修饰符是可以允许有变化的(子类方法访问范围需要大于等于父类的访问范围(重写是为了更好的覆盖,便于外部对象更好地访问))。与方法的参数名无关.重写方法的返回值类型应该与父类方法相同或者是父类方法返回值类型的子类(继承关系); 当子类重写父类的方法后,子类对象调用的是重写后的方法。 在子类中,可以定义与父类重名的属性(重名,类型任意,可以理解成属性重写)。 非虚方法:不能被重写或者说覆盖的方法,指的是构造方法、静态方法、私有方法和final 修饰的方法。 父类的构造方法不允许被继承,所以不能重写,但影响子类对象的实例化。父类的静态方法能被继承,不能重写,可以隐藏。父类的final方法能被继承,不能重写 虚方法:则是能被重写的方法,一般指的是实例方法。 static静态方法和final最终方法不能被重写;但静态方法在子类中可以通过隐藏()父类方法的方式重新实现。 重写方法访问权限必须大于等于父类方法。 成员变量(分为静态变量和实例变量)就是类里面的变量,不区分static。没有static的成员变量叫实例变量 当子类中定义了与父类相同的静态变量、实例变量或静态方法,并不会覆盖父类,而是同时存在,不过父类对应的静态变量、实例变量或静态方法被自动隐藏。 访问修饰符:公有的(public,任意类都可访问),私有的(private,只允许当前类访问),受保护的(protected,允许在当前类、同包子类/非子类、跨包子类调用,跨包非子类不允许),默认(允许在当前类、同包子类/非子类调用;跨包子类/非子类不允许调用) 静态方法的执行只看静态类型,而与实际类型无关(eg:若已定义父类Demo1和子类Demo2,且都有method()静态方法,实例化对象Demo1 d1=new Demo2();d1.method()执行的是父类Demo1的method静态方法而不是子类(实际类型)的)。重写的方法调用看的是实际类型,所以静态方法不能被重写 虚方法(实例方法)在运行期间会到方法表中去调用真实指向的方法 静态方法在运行期间直接调用方法区中静态方法,无需经过方法表,这也解释了静态方法的执行只看静态类型,而与实际类型无关 Java中为什么静态方法不能被重写?为什么静态方法不能隐藏实例方法?(https://blog.csdn.net/dawn_after_dark/article/details/74357049) 为什么子类中不能访问另一个包中父类中的protected方法?(https://blog.csdn.net/dawn_after_dark/article/details/74453915) Person student= new Student(); student.work(); 静态类型就是编译器编译期间认为对象所属的类型,这个主要根据声明类型决定,所以上述Person就是静态类型 实际类型就是解释器在执行时根据引用实际指向的对象所决定的,所以Student就是实际类型。 方法接受者就是动态绑定所找到执行此方法的对象,比如student。 编译时把对象的静态类型(声明类型)作为该方法的接受者。运行时则根据指令集再进行更改。 super关键字:父类对象的引用 满足继承关系的子类对象(子类对象实例化)是如何产生的?继承后的子类初始化顺序:jvm中加载类(父类静态成员(静态属性(加载静态方法并不调用/运行),静态代码块,执行顺序与书写位置有关)->子类静态成员->父类对象构造(创建对象时,先调用子类构造方法,在子类构造方法的第一行默认调用父类无参构造方法(隐式省略,也可super显式调用指定的父类构造方法).实例属性初始化(加载实例方法并不调用/运行)、构造代码块、构造方法,执行顺序与书写位置有关,构造方法最后执行完)->子类对象构造) 访问修饰符不影响成员加载顺序,跟书写位置有关 类的生命周期:装载、连接(验证、准备、解析)、初始化、使用(对象初始化、垃圾收集、对象终结)、卸载 静态成员是属于整个类的成员而不是属于某个对象的。 子类构造方法中默认调用父类无参构造方法,如果没有则会编译报错。可通过super()调用父类允许被访问的其他构造方法,super()必须放在子类构造方法有效代码第一行. super关键字:代表父类引用。1.访问父类成员方法。super.方法名();2.访问父类属性。super.属性名;3.访问父类构造方法。super(); 子类的构造的过程中必须调用其父类的构造方法。 若子类的构造方法中没有显式标注,则系统默认调用父类的无参的构造方法 若子类构造方法中即没有显式标注,且父类中没有无参的构造方法,则编译出错。 使用super调用父类指定构造方法,必须在子类的构造方法的第一行。 super不能在main方法里使用 ,main方法是静态方法,但Java语法规定,super不能在静态代码块中使用 super pk this: 一个构造方法中super和this不能并存,因它们都必须在有效代码的第一行.
对Object类进行介绍,同时讲解final关键字以及注解. Object类是所有类的父类 一个类没有使用extends关键字明确标志继承关系,则默认继承Object类(包括数组)(若A extends B,Object类是B的父类,A是B的子类是Object类的孙子类) Java中的每个类都可以使用Object中定义的方法 equals()方法测试:1.继承Object中equals方法时,比较的是两个引用是否指向同一个对象。2.子类可以通过重写equals方法的形式,改变比较的内容。 对于引用数据类型,==和equals都是比较内存中的地址是否相等.在String类中重写了equals方法,所以equals比较的是他们的值是否相等 toString()方法测试:1.输出对象名时,默认会直接调用类中的toString方法。2.继承Object中的toString方法时,输出对象的字符串表示形式:类型信息+@+地址信息.3.子类可通过重写toString方法的形式,改变输出的内容以及表现形式。 final关键字: final class:该类没有子类,即不能被继承 public final class/ final public class final 方法:该方法不允许被子类重写,但是可以正常被子类继承使用。final不能修饰构造方法 final 方法内局部变量:只要在具体被使用之前进行赋值即可,一旦赋值不允许被修改 final 类中成员属性:赋值过程:1.定义时直接初始化 2.构造方法中 3.构造代码块中 若未赋值则编译报错。 final修饰引用数据类型的变量,初始化之后不能再指向另一个对象(即引用地址不能改变),但对象的内容是可变的。 final可配合static使用,修饰方法/属性。eg:配置信息 使用final修饰可提高性能,但会降低可扩展性。 windows系统:alt+/快捷键显示提示信息 当变量指向一个对象时,这个变量就被称为引用变量 注解(JDK1.5版本引入的一个特性):一种标记,参与代码编译,可声明在包、类、属性、方法、局部变量、方法参数等的前面,用来对这些元素进行说明、注释。按运行机制分:源码注解(注解只在源码中存在,编译成.class文件就不存在)、编译时注解(注解在源码和.class文件中都存在)、运行时注解(在运行阶段还起作用,甚至会影响运行逻辑的注解)。按来源分:来自JDK的注解(eg:@Override)、来自第三方的注解(eg:第三方框架的注解:Spring注解@Autowired)、我们自定义的注解。 元注解:对Java中的注解进行介绍 注释:对代码无影响。对代码只起解释、说明的作用。
单例模式的特点,以及懒汉式和饿汉式两种实现方式。 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。 面向对象的23种基础设计模式,创建型模式:关注对象创建过程的设计模式.结构型模式:关注类和对象组合的设计模式.行为型模式:关注对象之间的通信过程的设计模式. 设计模式是基于场景的解决方案。若某个新场景的解决方案被认可,那我们可以定义一个新的设计模式。 单例模式:目的:使得类的一个对象成为该类系统中的唯一实例.定义:一个类有且仅有一个实例,并且自行实例化向整个系统提供。要点:1.某个类只能有一个实例2.必须自行创建实例3.必须自行向整个系统提供这个实例。实现:1.只提供私有的构造方法2.含有一个该类的静态私有对象(设置私有是不想除本类之外的类调用它)3.提供一个静态的公有方法用于创建、获取静态私有对象。代码实现方案:饿汉式(对象创建过程中实例化,特点:空间换时间,在类加载时实例化,调用时速度快,占空间时长。饿汉式线程安全)、懒汉式(静态公有方法中实例化,类内实例对象创建时并不直接实例化,直到第一次调用get方法时,才完成实例化操作.特点:时间换空间,在调用时实例化占空间时短,调用时用时长,不调用不实例化不占空间。懒汉式存在线程风险,控制风险方式:1.同步锁2.双重校验锁3.静态内部类4.枚举)。 1、一个Java对象的创建过程包括类初始化和类实例化两个阶段。 2、在实例化一个对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM(java虚拟机)立即进行加载并调用类构造方法完成类的初始化。在类初始化过程中或初始化完毕后,根据具体情况才会去对类进行实例化。 3、一个对象在可以被使用之前必须要被正确地实例化,在Java代码中,有很多行为可引起对象的创建,最为直观的一种就是使用new关键字来调用一个类的构造函数显式地创建对象,还有其他方法。 A a=new A(); 上面a是引用,用new A()创建了对象。由类构造对象的过程称为创建类的实例。 单例模式:优点:1.在内存中只有一个对象,节省内存空间2.避免频繁创建销毁对象,提高性能3.避免对共享资源的多重占用。缺点;1.扩展比较困难2.若实例化后的对象长期不利用,系统将默认为垃圾进行回收,造成对象状态丢失。使用场景:1.创建对象时占用资源过多,但同时又需要用到该类对象2.对系统内资源要求统一读写,如读写配置信息3.当多个实例存在可能引起程序逻辑错误,如号码生成器。
多态、抽象类、接口以及内部类的概念和应用。
多态是面向对象的核心特征 如果一个语言只支持类而不支持多态,只能说明它是基于对象的,而不是面向对象的。 把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化.即父亲的行为像儿子,而不是儿子的行为像父亲 什么是多态?多态在程序设计中的优势?在Java中如何实现多态? 多态指一个引用(类型)在不同的情况下的多种状态,也可理解为,多态是指通过指向父类的指针,来调用在不同子类中实现的方法。意味着允许不同类的对象对同一操作做出不同的响应,必要条件:1.满足继承关系2.父类引用指向子类对象 多态分两种:编译时多态(又称设计时多态),通过方法重载实现.运行时多态(Java中的多态多指运行时多态),程序运行时动态决定调用哪个方法。 向上转型(又称隐式转型/自动转型):父类引用指向子类实例,可调用子类重写父类的方法以及父类派生的方法,无法调用子类独有方法(父类中的静态方法无法被子类重写,所以向上转型后,只能调用到父类原有的静态方法).小类转型大类.向上转型中体现了动态绑定,动态绑定是指需要在程序运行中通过创建对象来绑定引用关系.向上转型和动态绑定可以实现多态. 向下转型(又称强制类型转换):子类引用指向父类对象,此处必须进行强转,可调用子类特有的方法,必须满足转型条件(1.满足继承关系2.父类引用指向子类对象。强转的引用本身是否指向子类实例)才能进行强转,若指向其它子类实例,强转能成功但是运行后报错.instanceof运算符判断一个对象是不是一个类型或一个类的子类的实例,返回true/false,提高向下转型的安全性,提高代码的强壮性。(也就是这个父类对象必须是指向该引用相同的子类对象的,不能是其他兄弟对象,也不能是指向父类的对象)相当于还原了这个子类对象他自己新增的属性和方法;若要想向下转型成功,就需有向上转型作为前提条件 为什么父类的静态方法不能被子类重写? 静态方法是类在加载时就被加载到内存中的方法,在整个运行过程中保持不变,因而不能重写.但非静态方法是在对象实例化时才单独申请内存空间,为每一个实例分配独立的运行内存,因而可以重写.静态方法通过类名调用,跟继承没有关系,重写是没有意义的。 在JVM中传入调用时可使用父类类型来接收子类的对象,这里涉及JVM的底层实现,并不是隐藏的向上转型! 多态的实现不仅能减少编码的工作量,还能大大提高程序的可维护性及可扩展性 实现多态的步骤包括:1.子类重写父类的方法2.定义方法时,把父类类型作为参数类型;调用方法时,把父类或子类的对象作为参数传入方法3.运行时,根据实际创建的对象类型动态决定使用哪个方法 抽象类:abstract定义抽象类,不允许实例化,只能被继承,可通过向上转型,指向子类实例.应用场景:某个父类只是知道其子类应该包含怎样的方法,但无法准确知道这些子类如何实现这些方法.优点:限制子类设计随意性(子类就算用super也不能调用父类的抽象方法,且必须重写父类抽象方法或子类成为抽象类),一定程度避免无意义父类的实例化。abstract可与public互换位置,但不能与class互换位置 抽象方法:abstract定义抽象方法,不需要具体实现,用;结束语句(只有抽象方法可用;代替大括号方法体,接口中的方法也是抽象方法),即不允许包含方法体(除非子类也是抽象类,否则抽象方法一定被子类重写,所以方法体无意义);子类中需重写父类的抽象方法,不写报错.或者子类也是抽象类. 包含抽象方法的类是抽象类,抽象类中可以没有抽象方法。 abstract关键字(修饰类时,此类能被继承,不能实例化本类.修饰方法时,此类必是抽象类,除子类也是抽象类,此方法必被子类重写)不能与static(只修饰内部类和方法和属性,类加载时加载到内存中,运行时保持不变,且abstract不修饰属性,所以不能共存)、final(修饰类时,能被继承,能实例化本类;修饰方法时,不能被重写;修饰属性时,abstract不修饰属性,所以不能共存)、private(无论修饰类、方法还是属性都作用与本类,不能继承,更不能重写,且abstract不修饰属性,所以不能共存)共存 接口: 问题:既然Java中只支持单继承,如何解决一个类型中需兼容多种类型特征的问题?以及多个不同类型在无法具有共同父类的前提下依然具有相同特征的问题? 接口定义了某一批类所需要遵守的规范.接口不关心这些类的内部数据,也不关心这些类里方法的实现细节,它只规定这些类里必须提供某些方法. 1.创建时与类不同,选interface.命名推荐以大写I开头,访问修饰符:public/默认,不能是protected.2.接口的方法是抽象方法不需要方法体,且可不需要abstract关键字,接口中的方法可不写public,但是访问修饰符默认是public.3.使用implements来实现接口4.若一个类实现接口,就必须重写接口中的所有方法或此类设置为抽象类(与子类必须重写父类抽象方法一样)5.接口中可包含常量,此常量在定义时必须初始化,默认public static fianl修饰,这几个修饰符可选择性/全部省略,(static意义:使接口常量在测试类中能直接调用,无需对象实例化.final意义:定义属性为常量),通过接口名.常量名调用.6.接口不能直接实例化,只能在实现接口的类中实现,且接口引用只能调用实现接口的类中重写的接口方法,而不能调用实现接口的类中独有的方法(特性类似向上转型),接口类型的引用变量来引用实现接口的类的实例是多态的一种表现形式.若想调用实现接口的类的特有方法属性需强制类型转换。 实现类与接口关联的目的是为了整个项目设计的规范,因为在实际开发中,是多个程序员分工合作的。某类中接口方法需要修改只重写此类中的接口方法即可,体现了程序的扩展性. 接口和类分开理解!“接口不是类,而是对类的一组需求描述。接口是一系列方法的声明,是一些方法特征的集合,是作为一种规范,它只能在类中实现,而不能直接实例化。 接口实质上就是一种特殊的抽象类,接口中定义的方法也是抽象方法,需要在实现它的类中进行重写。 满足实现接口的类只需重写接口中的部分方法的要求,在JDK1.8后可在接口中定义默认方法(default关键字不是访问修饰符,用接口类型的引用变量名.默认方法名调用,接口升级,可以改变接口,扩展接口功能.同时避免改变其他实现类.)和静态方法(static关键字不是访问修饰符,用接口名.静态方法名调用),都带方法体,实现类不需重写这些方法,实现类也可重写默认方法时,方法体中接口名.super.默认方法名;代表调用接口中默认的方法.实现类中不存接口中的静态方法亦不能重写静态方法. 实现类实现接口,需要实现接口中的普通方法(抽象方法),默认获得接口中的静态常量和默认方法等内容.(实现类不会获得接口中的静态方法;但子类能继承父类中静态方法,不能重写). Java中一个类可实现多个接口,接口之间用,分隔.implements实现放在extends继承后面. 关于多接口中重名默认方法处理的解决方案(成员:父类、子类即多接口的实现类、多接口):情况一:多接口有重名默认方法,父类没有此方法,子类需要重写此重名默认方法,不写报错.情况二:多接口有重名默认方法,父类也有此方法,子类不需重写此重名默认方法,不报错,也可重写. 关于多接口中重名常量处理的解决方案(成员:父类、子类即多接口的实现类、多接口):情况一:多接口有重名常量,父类没有此常量,子类需要自定义(不是重写)此重名常量,不写报错.情况二:多接口有重名常量,父类也有此常量,子类需重写此重名常量,不写报错.即不管父类有无此常量,子类都需自定义(不是重写)此重名常量. 在Java中规定,一个java文件中可以有很多类或者接口.但是public 修饰的类或者接口只能有一个,这个java文件的文件名必须是public修饰类名或者接口名一致. 接口也可以实现继承,并且可继承多个父接口. 类中静态属性和静态方法存在堆中,局部变量存在栈中,接口中的常量默认是static、final修饰,所有final修饰的常量都在JVM中的常量池.接口可以理解一种特殊的类,所以接口可参考类的内容.在jdk1.7后,常量池成为堆内存中的一部分,如String a=“abc"中,引用a是存储在栈内存的,指向常量池中的"abc”;栈内存属于线程等级,一般都不归于JVM内存模型中. 在Java中,可将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.与之对应包含内部类的类称为外部类. 内部类定义它是作为一个成员的位置上,特点是它会生成两个.class文件,比如:一个是外部的类Outer.class,另一个是 Outer I n n e r . c l a s s . 。 为 何 将 一 个 类 定 义 在 另 一 个 类 里 面 呢 ? 内 部 类 提 供 了 更 好 的 封 装 , 可 把 内 部 类 隐 藏 在 外 部 类 之 内 , 不 允 许 同 一 个 包 中 的 其 他 类 访 问 该 类 , 更 好 的 实 现 了 信 息 的 隐 藏 。 内 部 类 分 类 : 成 员 内 部 类 ( 又 称 普 通 内 部 类 , 最 常 见 的 内 部 类 ) 、 静 态 内 部 类 、 方 法 内 部 内 、 匿 名 内 部 类 . 成 员 内 部 类 : 1. 内 部 类 在 外 部 使 用 时 , 无 法 直 接 实 例 化 , 需 要 借 由 外 部 类 信 息 才 能 完 成 实 例 化 ( 获 取 内 部 类 对 象 实 例 的 方 式 : 方 式 1. 外 部 类 类 名 . 内 部 类 类 名 内 部 类 对 象 名 = n e w 外 部 类 类 名 ( ) . n e w 内 部 类 类 名 ( ) ; 方 式 2 : 外 部 类 完 成 实 例 化 后 , 外 部 类 类 名 . 内 部 类 类 名 内 部 类 对 象 名 = 外 部 类 对 象 名 . n e w 内 部 类 类 名 ( ) ; 方 式 3 : 外 部 类 完 成 实 例 化 后 , 外 部 类 类 名 . 内 部 类 类 名 内 部 类 对 象 名 = 外 部 类 对 象 名 . 获 取 方 法 ; 此 方 法 在 外 部 类 中 定 义 返 回 类 型 是 内 部 类 类 型 ) . 2. 内 部 类 的 访 问 修 饰 符 可 以 任 意 , 但 是 访 问 范 围 会 受 到 影 响 . 3. 内 部 类 可 直 接 访 问 外 部 类 的 成 员 ; 若 出 现 同 名 属 性 , 优 先 访 问 内 部 类 中 定 义 的 . 4. 可 使 用 外 部 类 类 名 . t h i s . 成 员 的 方 式 , 访 问 外 部 类 中 同 名 的 信 息 . 5. 外 部 类 访 问 内 部 类 信 息 , 需 通 过 内 部 类 实 例 , 无 法 直 接 访 问 . 6. 内 部 类 编 译 后 的 . c l a s s 文 件 命 名 : 外 部 类 类 名 Inner.class.。 为何将一个类定义在另一个类里面呢?内部类提供了更好的封装,可把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类,更好的实现了信息的隐藏。 内部类分类:成员内部类(又称普通内部类,最常见的内部类)、静态内部类、方法内部内、匿名内部类. 成员内部类:1.内部类在外部使用时,无法直接实例化,需要借由外部类信息才能完成实例化(获取内部类对象实例的方式:方式1.外部类类名.内部类类名 内部类对象名=new 外部类类名().new 内部类类名();方式2:外部类完成实例化后,外部类类名.内部类类名 内部类对象名=外部类对象名.new 内部类类名();方式3:外部类完成实例化后,外部类类名.内部类类名 内部类对象名=外部类对象名.获取方法;此方法在外部类中定义返回类型是内部类类型).2.内部类的访问修饰符可以任意,但是访问范围会受到影响.3.内部类可直接访问外部类的成员;若出现同名属性,优先访问内部类中定义的.4.可使用外部类类名.this.成员的方式,访问外部类中同名的信息.5.外部类访问内部类信息,需通过内部类实例,无法直接访问.6.内部类编译后的.class文件命名:外部类类名 Inner.class.。为何将一个类定义在另一个类里面呢?内部类提供了更好的封装,可把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类,更好的实现了信息的隐藏。内部类分类:成员内部类(又称普通内部类,最常见的内部类)、静态内部类、方法内部内、匿名内部类.成员内部类:1.内部类在外部使用时,无法直接实例化,需要借由外部类信息才能完成实例化(获取内部类对象实例的方式:方式1.外部类类名.内部类类名内部类对象名=new外部类类名().new内部类类名();方式2:外部类完成实例化后,外部类类名.内部类类名内部类对象名=外部类对象名.new内部类类名();方式3:外部类完成实例化后,外部类类名.内部类类名内部类对象名=外部类对象名.获取方法;此方法在外部类中定义返回类型是内部类类型).2.内部类的访问修饰符可以任意,但是访问范围会受到影响.3.内部类可直接访问外部类的成员;若出现同名属性,优先访问内部类中定义的.4.可使用外部类类名.this.成员的方式,访问外部类中同名的信息.5.外部类访问内部类信息,需通过内部类实例,无法直接访问.6.内部类编译后的.class文件命名:外部类类名内部类类名.class.7.内部类中可包含与外部类相同方法签名的方法. 方法签名由方法名和参数类型组成,可用来区分不同方法. 静态内部类:静态内部类对象可不依赖于外部类对象,直接创建.1.静态内部类中,只能直接访问外部类的静态成员,若需调用非静态成员,可通过外部类对象实例.2.静态内部类对象实例时,可以不依赖于外部类对象.方式:外部类类名.内部类类名 内部类对象名=new 外部类类名.内部类类名();3.可通过外部类类名.内部类类名.静态成员的方式,访问内部类中的静态成员(这些静态成员的访问权限需设置).4.当内部类属性与外部类属性同名时,默认直接调用内部类中的成员;若需访问外部类中的静态属性,则可通过外部类类名.属性的方式;若需访问外部类中的非静态属性,则可通过new 外部类类名().属性的方式; 静态内部类的定义:使用static来去修饰.可以有静态成员、也可以有非静态成员. 方法内部类:定义在外部类方法中的内部类,也称局部内部类.1.定义在方法内部,作用范围也在方法内(方法内定义的局部变量只能在方法里使用).2.和方法内部成员的使用规则一样,class前面不可添加public、private、protected、static.3.方法内部类中不能包含静态成员.4.类中可包含final、abstract(不建议包含abstract修饰成员,因包含了此类就需变成抽象类,即不能实例化,即不能通过实例化调用其方法)修饰的成员. 方法内部类编译后的.class文件略有不同.Out类名 1. c l a s s . . . 因 无 法 获 取 内 部 类 类 名 . 匿 名 内 部 类 : 1. 没 有 类 型 名 称 、 实 例 对 象 名 称 2. 编 译 后 的 文 件 命 名 : 外 部 类 类 名 1.class...因无法获取内部类类名. 匿名内部类:1.没有类型名称、实例对象名称2.编译后的文件命名:外部类类名 1.class...因无法获取内部类类名.匿名内部类:1.没有类型名称、实例对象名称2.编译后的文件命名:外部类类名数字.class.3.无法使用private\public\protected\abstract\static修饰,不能有抽象方法(有,与此类就成抽象类了有冲突).4.无法编写构造方法,可添加构造代码块,完成一些信息的定义初始化.5.不能出现静态成员.只可单一实现接口或继承父类. 匿名内部类没有名字,隐藏名字(隐藏抽象类的子类或接口的实现类的名字和其实例后对象的名字,将这个过程和方法的实现写到一起).对某个的实例只使用一次,此时这个类的名字重要性不大,通过将类的定义与类的创建,放到一起完成简化程序的编写.通常通过匿名内部类来简化对抽象类和接口实现的操作(可以理解为此类继承了抽象类或作为接口的实现类实现抽象类/接口的方法,此方法体自定义,且这个子类/实现类和实例化这个子类/实现类的对象没有名字).适用场景:只用到类的一个实例,类在定义后马上用到,给类命名并不会导致代码更容易被理解. 匿名内部类在定义创建时调用,不能多次调用,通常被设计为只使用一次. 匿名内部类编译后的.class文件与方法内部类类似.Out类名$1.class… 使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口.通常使用匿名内部类就相当于实现了接口或继承了父类.定义格式:(new 父类的构造方法或要实现的接口(){ 匿名内部类的类体;}); 易混淆:1.实例方法可与构造方法名字相同,但必须带返回值类型修饰.2.跨包调用类内的公有的静态方法可使用:包名.类名.方法名的形式.3.静态数据是属于类的,可通过对象来引用可编译通过,但一般都是通过类名来引用.父类和子类具有相同名称的静态方法时,当子类对象向上转型后,只能调用到父类原有的静态方法.4.接口中定义常量时必须初始化常量.5.创建对象时,先调用子类构造方法,在子类构造方法的第一行会调用父类的构造方法.可调用父类无参构造方法,也可通过super关键字调用指定的父类构造方法.