面向对象的三大特征继承、封装、多态,最编写具有面向对象思想的Java程序。
1.2.1 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语句)。
1.2.2 Java封装
什么是封装,以及如何在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{}中的代码,类加载时调用,优先于构造代码块执行,多个静态代码块顺序执行,无论产生多少类实例,静态代码块只执行一次。仅希望执行一次的代码可以放在静态代码块中。可以直接对当前类中静态属性赋值(不能声明静态属性,可以调用静态属性),不能直接对非静态属性赋值。
程序运行过程:静态代码块-主方法-(其他语句)-构造代码块-构造方法-(其他语句)
1.2.3 综合案例:学生信息管理
学习封装在面向对象中的应用。
直接声明在类体中的变量(成员属性),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.只定义对象/数组对象,在调用对象的信息时再初始化对象/数组对象。
1.2.4 Java继承(上)
继承的特点,如何在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不能并存,因它们都必须在有效代码的第一行.