课程总概
该门课程作为java入门学习的第二季,是在有一定的java基础上进行的进一步学习。由于该季涉及到了java的一些核心内容,所以相对第一季来说,课程难度有所提升。大致可将该季的课程分为五部分:第一部分,类和对象(第一章);第二部分,封装(第二章);第三部分,继承(第三章);第四部分,封装(第四章4-1~4-6);第五部分,项目练习(第四章4-7、第五章、第六章)。
一、类和对象
1、面向对象
即人关注事物信息。
2、类和对象
(1)类:即模子,确定对象将会拥有的特征(属性)和行为(方法)。
(2)类的特点:类是对象的类型,是具有相同属性和方法的一组对象的集合。
(3)属性:对象具有的各种特征(每个对象的属性都拥有特定值)。
(4)方法:对象执行的操作。
(5)类和对象的关系:类是抽象的概念,仅仅是模板;对象是一个你能够看得到、摸得着的具体实体。
3、定义类
(1)类的重要性:所有java程序都以类class为组织单位。
(2)类的定义:
① 定义类名;② 编写类的属性;③ 编写类的方法。
public class 类名{
//定义属性部分(成员变量)
属性1的类型 属性1;
属性2的类型 属性1;
……
//定义方法部分
方法1;
方法2;
……
}
4、使用对象
(1)创建对象:类名 对象名=new 类名();
(2)使用对象
引用对象的属性:对象名.属性
引用对象的方法:对象名.方法名()
PS:float类型数据后面要加上字母f,否则默认浮点数是double型。
5、成员变量和局部变量
(1)成员变量:在类中定义,用来描述对象将要有什么。
(2)局部变量:在类的方法中定义,在方法中临时保存数据。
(3)两者区别
成员变量:可以被本类的所有方法使用,也可以被与本类有关系的类中的方法使用,具有初始值0(作用域:整个类)。
局部变量:只能在当前方法中使用(作用域:本方法)。
(4)同名问题
① 在同一个方法中,不能有同名的局部变量,而在不同方法中可以;
② 两类变量同名时,局部变量拥有更高的优先级。
6、构造方法
(1)定义:是定义在java类中的一个用来初始化对象的方法,构造方法与类同名,且没有返回值。
(2)语法:public 构造方法名(){}
PS:① 无返回值类型;② ()中可以指定参数。
(3)注意
① 若无构造方法,会自动生成一个无参构造方法,可以自定义构造方法;
② 若已有构造方法,则不会自动生成无参构造方法;
③ 构造方法可以重载。
7、static
(1)静态变量
① static修饰的成员被称为静态成员或类成员,它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享,静态成员可以使用类名直接访问,也可以使用对象名进行访问,更推荐类名访问;
语法:类名.静态变量名
或 对象.静态变量名
② 使用static可以修饰变量、方法和代码块;
③ 静态成员属于整个类,当系统第一次使用该类时,就会为其分配内存空间,直到该类被卸载时才会进行资源回收。
(2)静态方法
① 静态方法可以直接调用同类中的静态成员,但不能直接调用非静态成员。如果想调用非静态变量,可以通过创建类的对象,然后通过对象来访问非静态变量;
语法:类名 对象名=new 类名();System.out.println(对象名.非静态变量名);
② 在普通成员方法中,则可以直接访问同类的非静态变量和静态变量;
③ 静态方法中不能直接调用非静态方法,需要通过对象来访问非静态方法。
(3)静态初始化块
① 在类的声明中,可以包含多个初始化块(用{}包含),当创建类的实例时,就会依次执行这些代码块。如果使用static修饰代码块,就称为静态初始化块;
② 静态初始化块只在类加载时执行,且只会执行一次,同时静态初始化块只能给静态变量赋值,不能初始化普通的变量成员;
语法:static{};
③ 程序运行时,静态初始化块最先被执行,然后执行普通的初始化块,最后才执行构造方法。
二、封装
1、封装
(1)面向对象的三大特性:封装性、继承性、多态性
(2)封装性
将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
(3)好处
① 只能通过规定的方法访问数据;
② 隐藏类的实例细节,方便修改和实现。
(4)实现步骤
点击Eclipse菜单栏的源码->点击生成getter和setter方法
2、包
(1)作用:管理java文件,解决同名冲突问题。
(2)定义:pacakage 包名;
PS:必须放在源程序的第一行,包名之间可以用“.”隔开(分级),如com.helloworld.hello。
(3)系统中的包
样式:java.(功能).(类)
① java.lang.(类) 包含java语言基础的类
② java.util.(类) 包含java语言中的各种工具类
③ java.io.(类) 包含输入输出相关功能的类
(4)包的使用
① 可以通过import关键字,在某个文件中使用其它文件中的类;,如:import com.helloworld.music.Myclass;
② java中,包的命名规范是全小写字母拼写;
③ 使用的时候不但可以加载某个包下的所有文件,如com.helloworld.*;
,也可以加载某个具体子包下的所有文件,如com.helloworld.music.*
;
3、访问修饰符
作用:可以修饰数属性和方法的访问范围。
4、this
(1)作用:代表当前对象。
this.属性
操作当前对象的属性
this.方法
调用当前对象的方法
(2)封装对象的属性的时候,经常会使用this。
5、内部类
(1)定义:内部类(Inner Class)就是定义在另外一个类里面的类,与之对应,包含内部类的类被称为外部类;
(2)作用
① 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类;
② 内部类的方法可以直接访问外部类的所有数据,包括私有的数据;
③ 内部类所实现的功能使用外部类同样可以实现,只是有时使用内部类更方便。
(3)种类
① 成员内部类;② 静态内部类;③ 方法内部类;④ 匿名内部类。
6、成员内部类
(1) Inner 类定义在 Outer 类的内部,相当于 Outer 类的一个成员变量的位置,Inner 类可以使用任意访问控制符,如 public 、 protected 、 private 等;
(2)Inner 类中定义的方法可以直接访问 Outer 类中的数据,而不受访问控制符的影响,如直接访问 Outer 类中的私有属性;
(3)定义了成员内部类后,必须使用外部类对象来创建内部类对象,而不能直接去 new 一个内部类对象,即内部类 对象名 = 外部类对象.new 内部类( );
;
(4)编译含有内部类的程序后,会发现产生了两个 .class 文件,其中,第二个是外部类的 .class 文件,第一个是内部类的 .class 文件,即成员内部类的 .class 文件总是这样:外部类名$内部类名.class
。
(5)注意
① 外部类不能直接使用内部类的成员和方法, 可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法;
② 如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,可以使用 this 关键字。
语法:外部类名.this.属性/方法
7、静态内部类
(1) 静态内部类不能直接访问外部类的非静态成员,但可以通过 外部类().成员
的方式访问 ;
(2)如果外部类的静态成员与内部类的成员名称相同,可通过外部类名.静态成员
访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员;
(3) 创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名= new 内部类();
。
8、方法内部类
(1)定义:方法内部类就是内部类定义在外部类的方法中,方法内部类只在该方法的内部可见,即只在该方法内可以使用。
(2)由于方法内部类不能在外部类的方法以外的地方使用,因此方法内部类不能使用访问控制符和static修饰符。
三、继承
1、继承
(1)定义:继承是类与类的一种关系(java中的继承是单继承,即只有一个父类)。
(2)继承的好处
① 子类拥有父类的所有属性和方法(private的不行);
② 实现代码复用。
(3)语法:class 子类 extends 父类{ }
PS:Eclipse可以在创建类的时候选择外层类和超类。
2、子类方法的重写
(1)子类可重写父类的方法,调用时会优先调用子类方法;
(2)需要① 返回值类型;② 方法名;③ 参数个数与类型都相同,才能称为子类方法的重写。
3、继承初始化顺序
(1)初始化父类再初始化子类;
(2)如果类中对属性进行了初始化,构造方法中也进行了初始化,则先执行初始化对象中属性,在执行构造方法中的初始化。
4、final
作用:使用final关键字做标识有“最终的”含义,它可以修饰类、方法、属性和变量。
(1) 修饰类:则不允许被继承;
(2)修饰方法:则不允许被重写;
(3)修饰属性:则该类的属性的两种方法只能选其一(类声明属性时赋值和在构造方法中赋值),即只能赋一次值;
(4)修饰变量:则它只能赋一次值,即常量。
5、super
作用:在对象内部使用,可代表父类对象,如super.属性/方法
。
(1)子类的构造过程当中必须调用其父类的构造方法,子类构造方法中会隐式显示 super();
语句;
(2)如果子类构造方法中没有显示调用父类的构造方法,则系统会默认调用父类的无参构造方法;
(3)如果显示地调用父类的构造方法,必须在子类的构造方法的第一行;
(4)如果子类构造方法中既无显式调用父类的构造方法,而父类又无无参构造方法,则编译出错。
6、Object类
(1)定义:Object类是所有类的父类,如果一个类没有使用extends关键字明确标识继承于另外一个类,那么这个类默认继承Object类,Object类中的方法,适合所有子类;
(2)toString()方法
对象调用toString方法返回的是对象的哈希code码(对象地址字符串),可以通过重写toString()方法表示出对象的属性。
(3)equals()方法
比较的是对象的引用是否指向同一块内存地址。
① 引用
如:Dog dog = new Dog();
其中的dog并不是所创建的对象,它只是对象的地址,称为引用。
② 一般情况下,比较两个对象时比较它的值是否一致,所以要重写
点击Eclipse菜单栏的源码->生成hashCode()和equals()方法
③ 语法:对象名.equals(另一个对象名);
结果为布尔值
(4)类对象关注的是属性;类的对象关注的是属性的值。
System.out.println(person.getClass());
//getClass方法用来返回对象所属类的相关信息,结果为class person.Person
System.out.println(person.getClass().getName());
//getName方法用来返回对象所属类的类名,结果为person.Person
四、多态
1、 定义
即对象的多种形态。
2、多态种类
(1)引用多态
父类的引用可以指向本类和子类的对象。
Animal obj1 = new Animal();
Animal obj2 = new Dog();
Dog obj3 = new Animal();//此行错误
(2)方法的多态
① 创建本类对象时,调用的方法为本类方法;
② 创建子类对象时,调用的方法为子类重写的方法或继承的方法;
③ 无法通过父类调用子类的独有方法。
3、引用类型转换
(1)向上类型转换:(隐式/自动类型转换)是小类型到大类型的转换;
(2)向下类型转换:(强制类型转换)是大类型到小类型的转换;
(3)instanceof运算符:用来解决引用对象类型转换的安全性问题;
Dog dog = new Dog();
Animal animal = dog;//自动类型提升
Dog dog2 = (Dog) animal;//向下类型转换
Cat cat = (Cat) animal;//1.编译时为Cat类型;2.运行时为Dog类型.两个类型不匹配,所以会报错.
改为
Dog dog = new Dog();
Animal animal = dog;
//判断animal对象所属类是否包Dogt类
//animal对象最先为Dog类,肯定是包含Dog类的
if(animal instanceof Dog){
Dog dog2 = (Dog) animal;
}
else Syatem.out.println("无法进行类型转换!");
//判断animal对象所属类是否包含Cat类
//animal对象最先为Dog类,肯定是不包含Cat类的
if(animal instanceof cat){
Cat cat = (Cat) animal;
}
else Syatem.out.println("无法进行类型转换!");
4、抽象类
(1)应用场景
① 在某些情况下,某个父类只是知道了其子类应该包含怎样的方法,但无法准确知道这些子类如何实现这些方法;
② 从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为子类的模板,从而避免了子类设计的随意性。
(2)作用:限制规定子类必须实现某些方法,但不关注实现细节。
(3)使用规则
① abstract 定义抽象类;
② abstract 定义抽象方法,只有声明,不需要实现(无方法体);
③ 包含抽象方法的类是抽象类;
④ 抽象类可以包含普通的方法,也可以没有抽象方法;
⑤ 抽象类不能直接创建对象,它可以创建引用变量指向子类对象。
如:public abstract class Telphone;
使用
Telphone tel1 = new Cellphone();
Telphone tel2 = new Smartphone();
或者直接
Cellphone tel1 = new Cellphone();
Smartphone tel2 = new Smartphone();
PS:一般抽象类名为大写A开头,再加上类名,如:APerson。
5、接口
(1)定义:接口是一种特殊的类,由全局常量和公共的抽象方法组成。
(2)类与接口:类是一种具体实现体,而接口定义类某一批类所需要遵守的规范,接口不关心这些类的内部数据,也不关心这些类里方法的实现细节,她只规定这些类里必须提供某些方法。
(3)定义的语法
[修饰符] abstract interface 接口名 [extends 父接口1,父接口2...]
//[]内为可选项;abstract 若未显式输入,则系统会自动加上
{
public static final 数据类型 常量名1;
//属性必须为常量,即使输入时未添加public static final,系统也会自动添加
public static final 数据类型 常量名2;
...
public abstract 方法1{ }
//方法必须为抽象方法,即使输入时未添加public abstract,系统也会自动添加
public abstract 方法2{ }
...
}
PS:接口就是用来被继承的、被实现的,修饰符一般建议用 public ,不能用 private 和 protected 修饰接口。
(4)接口的使用
① 一个类可以实现一个或多个接口,java中一个类只能继承一个父类是不够灵活的,通过实现多个接口可以作补充。
② 实现接口的语法
[修饰符] abstract class 类名 [extends 父类] implements 接口1,父接口2...
//如果继承了父类,则extends和implements不能互换位置
{
类体部分;//如果继承了抽象类,需要实现继承的抽象方法,且要实现接口中的抽象方法
}
PS:通常会在接口名前加上字母“I”。
③ 接口的引用可一个指向实现了接口的对象(类似于父类与子类的使用);
④ 接口在使用过程中还经常与匿名内部类配合使用,匿名内部类就是没有名字的内部类,多用于关注实现而不关注实现类的名称,只是在使用时定义。
接口名 i = new 接口名(){
public void method(){
System.out.println("匿名内部类实现接口的方式");
}
};
或者直接
new 接口名(){
public void method(){
System.out.println("匿名内部类实现接口的方式");
}
}.method();
五、项目练习
1、UML简介
(1)定义:(Unified Modeling Language)又称统一建模语言或标准建模语言,是一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化支持。
(2)UML图示:UML2.2中一共定义了14种图示(diagrams)。
(3)常用UML图
① 用例图(The Use Case Diagram)
用例图能够以可视化的方式,表达系统如何满足所收集的业务规则,以及特定的用户需求等信息。
② 序列图(The Sequence Diagram)
用于按照交互发生的一系列顺序,显示对象之间的这些交互。
③ 类图(The Class Diagram)
UML类图、业务逻辑和所有支持结构一同被用于定义全部的代码结构(类与类之间的关系,类中有哪些属性和方法)。
(4)建模工具
Visio、Rational Rose、PowerDesign(应用最广)
① - 代表私有,+ 代表公有
② 《override》 代表重写
③ 空心箭头 代表继承(子->父)
④ 虚线箭头 代表实现接口(子->接口)
PS:点击菜单栏的语言->点击生成代码,会根据图形生成代码。
2、项目分析
(1)数据模型分析
① 通过对现实世界的事与物主及要特征的分析、抽象,为信息系统的实施提供数据存取的数据结构以及相应的约束。
② 数据结构组成:操作(方法)、属性。
(2)业务模型分析
① 在设计应用程序之前,应该明确该应用程序必须执行哪些业务。分析业务需求是应用程序开发中最重要的步骤之一。
② 确认业务需求的目的在于创建一个能同时满足零售商和消费者需要的解决方案。
(3)显示和流程分析
① 显示:用户可以看到的信息提示界面。
② 流程:显示信息执行的流程、步骤。
3、嗒嗒租车项目
(1)题目
(2)项目分析
(3)源码
//Car.java文件
package car;
//定义Car抽象类
public abstract class Car {
String name;
int rent;
public String getName() {
return name;
}
public int getRent() {
return rent;
}
public int getPeopleCapacity() {
return 0;
}
public int getGoodCapacity() {
return 0;
}
}
//Passenger.java文件
package car;
//定义继承于Car类的Passenger类
public class Passenger extends Car {
int peopleCapacity;
public Passenger(String name,int peopleCapacity,int rent){
this.name=name;
this.peopleCapacity=peopleCapacity;
this.rent=rent;
}
public int getPeopleCapacity(){
return peopleCapacity;
}
}
//Trunk.java文件
package car;
//定义继承于Car类的Trunk类
public class Trunk extends Car {
int goodCapacity;
public Trunk(String name,int goodCapacity,int rent){
this.name=name;
this.goodCapacity=goodCapacity;
this.rent=rent;
}
public int getGoodCapacity(){
return goodCapacity;
}
}
//Pickup.java文件
package car;
//定义继承于Car类的Pickup类
public class Pickup extends Car {
int peopleCapacity;
int goodCapacity;
public Pickup(String name,int peopleCapacity,int goodCapacity,int rent){
this.name=name;
this.goodCapacity=goodCapacity;
this.peopleCapacity=peopleCapacity;
this.rent=rent;
}
public int getPeopleCapacity(){
return peopleCapacity;
}
public int getGoodCapacity(){
return goodCapacity;
}
}
//number.java文件
package car;
//定义记录订单信息number类
public class number {
int xuhao;//序号
int shuli;//数量
int tians;//天数
public number(int xuhao,int shuli,int tians){
this.xuhao=xuhao;
this.shuli=shuli;
this.tians=tians;
}
public int getXuhao() {
return xuhao;
}
public void setXuhao(int xuhao) {
this.xuhao = xuhao;
}
public int getShuli() {
return shuli;
}
public void setShuli(int shuli) {
this.shuli = shuli;
}
public int getTians() {
return tians;
}
public void setTians(int tians) {
this.tians = tians;
}
}
//Initial.java文件(主方法所在文件)
package car;
//导入java.util.Scanner包,用来获取用户输入的数据
import java.util.Scanner;
public class Initial {
//用来关闭创建的Scanner类的对象
@SuppressWarnings("resource")
public static void main(String[] args){
//定义数组,用来储存车辆信息
Car [] cars={
new Passenger("奥迪A4",4,500),
new Passenger("马自达",4,400),
new Pickup("皮卡雪",4,2,450),
new Passenger("金龙",20,800),
new Trunk("松花江",4,400),
new Trunk("依维柯",20,1000)
};
System.out.println("***欢迎使用嗒嗒租车系统***");
System.out.println("您是否需要租车服务?(Y/N)");
//获取输入的字符并验证
String flag=new Scanner(System.in).next();
if(flag.equals("N")||flag.equals("n")){
System.out.println("十分感谢您的信赖,欢迎再来!");
System.exit(0);//退出系统
}
//输出车辆信息以供选择
else{
System.out.println("有以下几种车型供您选择:");
System.out.println("序号"+'\t'+"车型"+'\t'+"租金"+'\t'+"载客量"+'\t'+"载货量");
}
for(int i=0;i<cars.length;i++){
System.out.println((i+1)+"\t"+cars[i].getName()+"\t"+cars[i].getRent()+"\t"+cars[i].getPeopleCapacity()+"\t"+cars[i].getGoodCapacity());
}
//创建记录订单信息的数组并把所有数据赋值为0
final int Max=100;
number []numbers=new number[Max];
for(int i=0;i<numbers.length;i++){
numbers[i]=new number(0,0,0);
}
//使用while循环以重复进行车辆的选择
String contin="Y";
while(contin.equals("Y")||contin.equals("y")){
//利用 while 循环判断输入的序号正确与否
System.out.println("请输入您要租用的车辆的序号:");
int num=new Scanner(System.in).nextInt();
while(num<1||num>cars.length){
System.out.println("输入错误!请输入大于或等于1且小于或等于"+cars.length+"的整数!");
num=new Scanner(System.in).nextInt();
}
//利用 while 循环判断输入的数量正确与否
System.out.println("请输入您要租用"+cars[num-1].getName()+"的数量:");
int num1=new Scanner(System.in).nextInt();
while(num1<0){
System.out.println("输入错误!请输入大于或等于0的整数!");
num1=new Scanner(System.in).nextInt();
}
//利用 while 循环判断输入的天数正确与否
System.out.println("请输入您要租用"+cars[num-1].getName()+"的天数:");
int num2=new Scanner(System.in).nextInt();
while(num2<0){
System.out.println("输入错误!请输入大于或等于0的整数!");
num2=new Scanner(System.in).nextInt();
}
numbers[num-1].setShuli(num1);
numbers[num-1].setTians(num2);
System.out.println("您是否需要继续租车?(Y/N)");
contin=new Scanner(System.in).next();
}
//输出租车清单
System.out.println("以下是您的租车清单:");
System.out.println("车型\t租车数量\t租车天数\t载客量\t载货量\t租金小计");
int addShuli=0;
int addTians=0;
int addPeopleCapacity=0;
int addGoodCapacity=0;
int addRent=0;
//利用for循环把租车信息输出,并算出合计的信息
for(int i=0;i<numbers.length;i++){
if(numbers[i].getShuli()!=0&&numbers[i].getTians()!=0){
System.out.println(cars[i].name+"\t"+numbers[i].getShuli()+"\t"+numbers[i].getTians()+"\t"+cars[i].getPeopleCapacity()*numbers[i].getShuli()+"\t"+cars[i].getGoodCapacity()*numbers[i].getShuli()+"\t"+numbers[i].getShuli()*numbers[i].getTians()*cars[i].getRent());
addShuli+=numbers[i].getShuli();
addTians+=numbers[i].getTians();
addPeopleCapacity+=cars[i].getPeopleCapacity()*numbers[i].getShuli();
addGoodCapacity+=cars[i].getGoodCapacity()*numbers[i].getShuli();
addRent+=numbers[i].getShuli()*numbers[i].getTians()*cars[i].getRent();
}
}
System.out.println("总租车数\t租车总天数\t总载客量\t总载货量\t总租金");
System.out.println(addShuli+"\t"+addTians+"\t"+addPeopleCapacity+"\t"+addGoodCapacity+"\t"+addRent);
System.out.println("感谢您的光顾,欢迎再来!");
System.exit(0);//退出系统
}
}
心得体会
此次Java入门第二季课程主要学习的是面向对象的重要思想,由于之前在学习c++的时候学习了这种思想,所以,虽然此次的学习深度加深了,但是难度并没有提升很多。
经过此次的学习,我有如下几个心得体会:
1、学习时要做到心无旁骛
在此次课程的学习过程中,我总是会被身边的事情或者人所影响,不能静下心来认真地学习,导致学习的效率下降。以后学习时,尽量做到身边没有人,把自己封闭起来认真学。
2、要按照学习计划来学
之所以做计划,是为了能够井井有条地做好每一件要做的事,不会手忙脚乱。按照计划学习,可以使学习的效率更高。此次的学习被一些突发的事情打乱,所以没能高效率地按计划完成,导致学习总结一直拖,拖到现在才写完。
3、编程前要先搭好框架
编程前,你要先思考,你的程序要实现的功能是什么,需要建立哪些类,你需要哪些数据,你需要哪些方法,搭好一个整体的框架,然后再具体思考如何实现这些功能。
4、一定要掌握面向对象的思想
面向对象的编程思想是目前大多数计算机语言的核心思想,这是将来做项目的基础,目前只是小试牛刀,还需要进行深入学习。