1. 对象概念
什么是面向对象
1. 面向对象思想将客观世界中的事物描述为对象,并通过抽象思维方法将需要解决的实际问题分解成人们易于理解的对象模型,然后通过这些对象模型来构建应用程序的功能
2. 面向对象开发的一些概念: 类、对象、继承、封装、多态等
什么是对象
1. 一切客观存在的事物都是对象,比如这辆汽车、这个人、这间房子、这张桌子、这株植物、这张支票、这件雨衣。 概括来说就是:万物皆对象。
对象的组成
1. 属性(名字,性别,年龄)
2. 行为(跑,跳,放技能,吃,骂人)
一个对象可以成为另一个对象的属性
1. 电动自行车和马达,马达是一个对象,电动自行车又是一个对象。
2. 什么是类
2.1. 类是什么?
类是对大量对象共性的抽象
类是客观事物在人脑中的主观反映
类是创建对象的模板(在类里创建对象)
2.2. 类由两部分组成
属性、对象
例如学生类,凡是学生,都有学号、姓名、班级等,这些都是描述学生特征的,称为学生类的属性;凡是学生,都有回答问题、做实验等行为
2.3. 类和对象的关系
类是一个族群,对象是族群中的个体
2.4. 程序实例
创建一个Person类
new相当于复制,每个new出来的对象都是独立的创建的一个人类
在主函数中创建一个对象,并赋予属性,然后调用方法
3. Java中类的定义及使用
定义一个类的语法
类体由两部分组成:成员变量、成员方法
成员变量的声明
成员方法的声明:其实就是类似函数,只不过叫法不同
类的使用
通过类创建一个对象
1. 语法 类型 变量名 = new 类类型名();
2. 如 Student stu = new Student(); Student是我们自己定义的类型
3. new相当于复制,每个new出来的对象都是独立的为对象的成员变量赋值
4. 语法:对象名.属性名 = 属性值
调用对象的成员方法
1. 语法:对象名.方法ming(参数……);
4. New新建类
该图利用new新建的类,经过了向上转型,本质是子类,但用的使用只能当做父类用,不能访问子类中的属性和方法
5. 对象与类
在一个类中可以调用其他类的对象
变量、方法返回值、方法参数都可以是对象,万物皆对象
6. 方法重载
重载(overloading)
同一个类中定义了多个方法名相同而参数不同的方法
Person的类
主方法实现
7. 构造方法
Java语言通过类的构造方法构建对象,构造方法与普通方法的声明类似,但是构造方法有一些特征:
1. 构造器的名称必须与类名相同。
2. 构造器没有返回类型,包括关键字void也不能有。
3. 任何类都含有构造器。如果没有显式地定义类的构造器,则系统会为该类提供一个默认的构造器。这个默认的构造器不含任何参数。一旦在类中显式地定义了构造器,系统就不会再为这个类提供默认的构造器了。
4. 不写返回值类型,返回值是一个对象
5. 构造方法只有在被new的时候调用
Person类
main方法实现
构造方法的使用
通过使用new运算符构造对象
构造方法除了用于实例化对象之外,可以通过构造方法为成员变量赋值
8. 面向对象实例之饲养员喂食
8.1. 思路
可见我们需要创建饲养员类和动物类还有食物类
8.2. 实现
8.2.1. 饲养员
看饲养员类中的方法传入的参数,是一个动物类和一个食物类,可见这非常符合人类的思维方式,就这么用就完了。
8.2.2. 动物类
8.2.3. 食物类
8.2.4. main方法
9. 类属性和实例属性
9.1. 什么是类成员
使用static修饰的成员方法和成员变量称为类成员
使用static修饰的成员变量叫做类变量
使用static修饰的成员方法叫做类方法
类成员是不依赖对象存在的,属于类属性,可以通过类直接对其进行访问。
所有的对象共享一个类成员。
9.2. 什么是实例变量
未使用static修饰的成员方法和成员变量称为实例成员
未使用static修饰的成员变量叫做实例变量
末使用static修饰的成员方法叫做实例方法
只有每个对象才可以使用
9.3. 实例变量与类成员示意图
从这个图中可以看出,每创建一个对象就复制一个类模板,每个对象中的属性相互独立,但是使用static修饰的类成员,只有一个,它不依赖对象,所有的对象偶可以访问他,即使没有对象,也可以通过类进行访问。
9.4. 实例变量和类变量的区别
所有该类的对象共享同一个类变量,但是每个对象都会有自己独特的实例变量
所有该类的对象都能改变类变量的值,只要有一个对象改变类变量的值,所有对象访问类变量时,访问的值就是改变的值
实例变量在使用前必须创建一个对象,根据对象名.变量名使用,但是类变量可以不创建对象
9.5. static作用(静态代码块)
静态代码块
1. 是一个以static为前导的代码块,一般用于为类的工作做一些初始化工作,如初始化一些静态变量。
2. 一个类中可以有许多静态初始化块,并且它们可以出现在类体的任何地方。运行时系统会保证静态初始化块会按照它们在源代码中出现的顺序被调用
执行顺序
静态代码块随着类加载而加载,有多个静态代码块的,按代码块前后顺序加载,一个代码块,只执行一次。
1. 静态代码块和main在一个类中,优先执行静态代码块
2. main方法写在类的外边,用new或调用都会导致类被加载执行,并且只执行1次,静态代码块没有被执行,Student类
静态代码块被执行
9.6. static和final static
这两个是不同的概念,final static是定义一个静态的并且不能修改的变量。
10. 类方法和实例方法
10.1. 程序演示
10.2. 示意图
10.3. 细节说明
类方法:里面可以使用静态变量和类方法 但是不能使用实例属性和实例方法,因为在方法被初始化的时候还并不存在实例,只用创建对象后才有实例,具体看示意图。
10.4. 类方法
使用static修饰(静态方法),属于整个类的,不是属于某个实例的
里面可以使用静态变量,也可以调用静态方法,但是不能使用实例属性(变量)或实例方法,因为还没有实例(对象)存在
一个类中的方法可以互相调用。但要注意:实例方法可以调用该类中的其他方法,例如,a()可以调用b()。类方法只能调用其他类方法,不能调用实例方法。例如,name()只能调用name1()而不能调用a()/b()。
当类文件加载到内存时,实例方法不会被分配内存空间,只有在对象创建之后才会分配。而类方法在该类被加载到内存时就分配了相应的内存空间。
类方法只能访问其他static方法。
类方法只能访问其他static数据,类变量。
10.5. 实例方法
1. 不用static修饰
2. 实例方法既能对类变量操作也能对实例变量操作。
10.6. 调用
类名.方法名([参数])调用,可以不创建对象
实例方法使用对象名.方法名([参数])调用,必须创建对象调用类方法
10.7. 调用实例方法
11. this的使用
在类中如果局部变量和成员变量不重名,那直接写成员变量名时,this. 被隐藏了,this表示当前的对象
用于一个类中局部变量和成员变量重名,this.变量名 = 成员变量
this是一种特殊的引用,指向当前对象
this的两种使用方法
1. 如果发生局部变量与成员变量命名冲突时,可以通过this.成员变量名的方式区分实例变量和局部变量
2. 一个构造方法中需要调用同一个类的另一个构造方法,可以通过this()的方式调用,但this()必须要书写在第一行
通过this.成员变量名调用隐藏的成员变量
this([参数列表])调用本一个类的另外一个构造方法
12. 封装
封装的概念
封装属性/方法,使其只能在类中使用,出了类就不可以访问
封装的分类
1. 对属性的封装:将属性设置为private(私有),限制其只能在类的内部使用
2. 对方法的封装:对于方法的封装,将外部可以访问方法设置为public,将外部不能访问的方法设置为private
快速生成set/get方法,右键/选择如下
1. 全选,也可以根据自己的要求进行选择
2. 生成效果
封装属性的使用方法
name、age、sex都被封装起来了,只能用公开的方法,修改或获取(类似函数,传参数/或取返回值)
封住之后的使用
13. 继承
什么是继承
1. 一个新类可以从现有的类派生,这样的过程叫做继承
2. 那么在继承的过程中,新类被称为子类,现有的类被称为父类,子类将会继承父类的属性和行为。
继承的语法
[修饰符] class 子类类名 extends 父类类名{类体部分}
子类的扩展
子类除了可以拥有父类非私有的属性和方法外,也可以扩展自己的属性和方法
继承的使用细节
1. Java中的继承是单继承,也就是一个类只能有一个父类。
2. 如果一个类没有显式的继承某一个类,那么它有一个默认的父类是java.lang.Object类
3. Java继承了父类非私有的成员变量和成员方法,但是请注意:子类是无法继承父类的构造方法的
13.1. 访问修饰符
访问修饰符对成员变量和成员方法的访问限定
13.2. super关键字
super代表的是父类对象
super的使用方式
1. super.属性名 用于在子类中调用父类被隐藏的同名实例变量
2. super([参数列表]) 用于在子类的构造方法中调用父类的构造方法
super.变量名的使用
super([参数列表])的使用
每一个子类的构造方法在没有显式调用super(),系统都会提供一个默认的super()
super() 书写在第一行
可以在子类构造方法中显式调用super(),完成对特定父类构造方法的调用
如果父类的构造方法中有带参数的,那子类的构造方法至少有一个结构跟父类的相同
13.2.1. 注意事项
父类中的参数可以为父类类型
在访问时,可以进行如下操作
记住一句话,子类属于父类,但父类不属于子类,因此可以进行第11和13行操作
14. 重写方法
重写 override
子类从父类继承的某个实例方法无法满足子类的功能需要时,需要在子类中对该实例方法进行重新实现,这样的过程称为重写,也叫做覆写。
方法重写的要求
1. 子类重写方法的访问修饰范围必须大于或者等于父类对应方法的访问修饰符范围
2. 除修饰符外,重写方法的其他部分必须和父类保持一致
15. 向上转型与向下转型
15.1. 向上转型
15.1.1. 概述
有一个动物类(Animal),它有两个子类Dog和Cat,有些时候我们想要一个对象,这个 对象可能是Dog也可能是Cat,这个时候我们可以这样:
1. 声明一个动物a:Animal a ;
2. 动物a是一只猫:a=new Cat();
3. 动物a是一条狗:a=new Dog();
4. 这是用子类的实例赋值给父类变量,这种情况称为向上转型。
向上转型后,原来子类的属性和方法不可以被使用,转型后只被当做父类使用
public class Test {
public static void main(String[] args) {
//Students1是Students 的子类
Students1 s = new Students1("1234","张山");
//向上转型
Students s1 = (Students)s;
s.say(); //报错,不可以访问子类属性和方法
System.out.println(s1.code);
}
}
public class Students1 extends Students{
String code1 = "12345";
String name;
public Students1(String code, String name) {
super(code, name);
System.out.println("OK");
// TODO Auto-generated constructor stub
}
public boolean say(Students s) {
//Students1 st = (Students1)s;
return code.equals(s.code);
}
}
public class Students{
String code; //学生学号
private String name; //学生姓名
public String getCode() {
return code;
}
public Students(String code , String name) {
this.code = code;
this.name = name;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//equals默认判断内存地址,有时不符合业务逻辑,需要重写
public boolean equals(Object obj) {
Students s = (Students) obj;
return this.code.equals(s.code);
}
}
15.1.2. 向上转型程序示意
15.1.3. 总结
向上转型,转型后的对象完全当做父类使用,当子类和父类共有某个方法时,可以直接方法子类方法而父类的方法将会被屏蔽,但是当访问子类独有的方法的时候,会报错,不可以访问。
15.2. 向下转型
15.2.1. 概述
把一个父类对象强制转换为一个子对象
就是一个狗通过向上转型后,转成动物类(父类),此时这个动物是一个狗,当向下转型后,狗就又变回了自己。
下图为错误的写法,应该写成Dog c = (Dog)a;
该图解析:一个人说这条狗是一个动物(向上转型),另一个人说这个动物是一条狗(向下转型),如果说这个动物是个猫(大错特错)
向下转型后,不可以访问父类属性和方法,只被当做子类使用,向下转型的前提是,经过向上转型(图1),该图中的第一条语句经过了向上转型,本质是是Students1,但此时被当做Students,经过下面的向下转型,还原到本质,当被用作子类使用时,可以访问父类的非私有属性和方法(图2)
图1
图2
15.2.2. 向下转型程序示意
15.2.3. 总结
1. 当被用作子类使用时,可以访问父类的非私有属性和方法
2. 子类通过向上转型为父类时,用时是当父类用,但本质是子类,不可以访问子类中的属性和方法,由于本质是子类,因此就可可通过向下转型变为子类
3. 当被用作子类时,可以访问父类的非私有属性和方法
4. 如果父类的本质还是父类(没有经过向上转型),那只能当做父类使用,不能向下转型
5. 向下转型一定要类型匹配,比如原先的动物是一条狗,你现在要向下转型变成一只猫,这是不符合逻辑的。
16. 多态
什么是多态
1. 多态顾名思义即为多种形态的意思
2. Java中多态的含义:发送消息给某个对象,让这个对象自行决定采用哪种行为响应这个消息
3. 子类对象的引用赋值给父类引用变量来实现动态的方法调用
Java中形成多态的前提
1. 继承
2. 重写
3. 向上转型
当利用向上转型时,利用动物对象a.eat(),如果相应子类中有该方法,则输出该方法,没有则输出父类中的eat()方法
多态的作用
1. 提高代码的可重用性
2. 降低模块之间的耦合度:上面Cat、Dog、Animal类之间的关系不大
多态程序示例
17. 抽象类和抽象方法
形状类Shape需要提供用于计算面积和周长的方法,但是形状本身没有被确定,那么计算周长和面积的方法就无法确定,此时我们就需要使用抽象类和抽象方法。
由于Shape类计算周长和面积的方法无法确定,那么就可以将这样的方法声明为抽象的,以便在具体的子类中进行实现。
抽象方法的声明
1. [修饰符] abstract 返回值类型 方法名([参数列表]);
2. 注意:因为抽象方法无法确定具体执行的功能,所有抽象方法没有方法体,需要在小括号后加上分号
因为抽象类不是一个具体的类,所以无法实例化,但是抽象类可以用于声明对象
抽象类可以被继承,在子类中实现抽象类的所有抽象方法,以达到抽象类的具体化
具体化后的子类方法就可以用来创建对象了
第14行属于向上转型,不可以调用子类的属性,可以调用抽象父类的子类方法(父类中的抽象方法)
18. 接口
接口注重使用,给你一个接口你拿来用就行了,接口就是一种约定,一种标准化(比如插座的插口,国际标准插口)
Java与生活联系非常紧密
在软件工程中,经常将一个大的项目分由不同的开发小组共同开发,各个小组的开发工作是并行的。在很多时候,对于不同小组的程序员来说,清楚地说明各自的软件如何相互作用,并就此达成统一“约定”是很重要的。这种情况下,每一小组都可以在对其他小组怎么编写代码一无所知的情况下,就能编写自己的代码,并且各自小组编写的代码能很好的协同工作。接口就是这样的“约定”。
接口只是一个设计,它不能直接使用,需要具体实现
接口中只能有常量和抽象方法
18.1. 接口概述
- 接口用来制定规范
- 接口可以有很多种实现
例如:USB接口,USB灯,USB风扇,USB鼠标,USB键盘等等。 - 接口可以用来声明对象
USB a= new USB风扇(); - 接口是不具体的,不能用来直接创建对象
- 接口是一种规范,是抽象的,就相当于一张设计图,一份图纸,不能直接创建对象,具体怎么实现我不管。
在Java中接口不仅仅是程序开发过程中“约定”,更是更加抽象化的抽象类
18.2. 接口的定义
[修饰符] interface 接口名{[常量];[抽象方法]}
18.3. 接口的实现
定义类时通过implements关键字实现接口
[修饰符] class 类名 [extends 父类名] [implements 接口1,接口2,……]{类体部分}
18.4. 调用接口
18.5. 接口示意图
18.6. USB接口练习
先设计USB接口规范
//定义USB规范
public interface Usb {
public abstract void run();
public abstract void end();
}
然后各个厂商可以使用该USB接口规范,比如台灯厂商,使用USB接口规范
//台灯制作厂商
public class Light implements Usb {
public void run() {
System.out.println("来风啦");
}
@Override
public void end() {
System.out.println("风停啦,欢迎使用本风扇");
}
}
数据线生产商采用USB接口规范
//数据线生产商
public class Wire implements Usb {
@Override
public void run() {
System.out.println("开始传输数据");
}
@Override
public void end() {
System.out.println("数据传输停止");
}
}
在main方法中调用,先声明一个USB设备,因为以上这些实现了USB规范协议,因此都是USB设备,可以新建一个USB设备,然后让这个设备运行
public class Test {
public static void main(String[] args) {
Usb u; //声明一个USB设备
u = new Wire(); //因为Wire实现了USB规范协议,因此Wire是USB设备
u.run();
u.end();
}
}
18.7. 多重继承
一个类可以实现多个接口,一个类可以继承多个接口,从而解决了Java单继承的缺点。
public 和abstract默认添加上
1. m1只能实现接口MyInterface中的方法
2. m2只能实现接口MyInterface1中的方法
3. m3能实现两个接口中的方法
public interface MyInterface {
//设计一个标准,这个标准里,有说话这个功能
public final static String name = "小李";
public abstract void say();
}
public interface MyInterface1 {
public abstract void eat();
//void eat();
}
public class Myclass implements MyInterface,MyInterface1{
public void say() {
System.out.println("实现接口MyInterface中方法");
}
@Override
public void eat() {
m2.eat();
//能说能吃
Myclass m3 = new Myclass();
m3.eat();
m3.say();
}
}
在Java中类之间的继承关系是单继承,也就是说一个类有且只能有一个父类。
而Java中的接口实现了多继承,也就是说一个接口可以有多个父接口
MyInterface接口继承了MyInterface1接口,说明MyInterface接口包含了MyInterface1接口的所有内容
public interface MyInterface extends MyInterface1{
//设计一个标准,这个标准里,有说话这个功能
//Java中的接口实现了多继承,一个接口可以有多个父接口
public final static String name = "小李";
public abstract void say();
}
public interface MyInterface1 {
public abstract void eat();
//void eat();
}
public class Myclass implements MyInterface{
public void say() {
System.out.println("实现接口MyInterface中方法");
}
@Override
public void eat() {
System.out.println("不写这个MyInterface1中的方法不行");
}
}
public class Test {
public static void main(String[] args) {
MyInterface m1 = new Myclass();
m1.say();
m1.eat();
}
}
接口的作用
1. 提高程序的重用性
2. 提高程序的可扩展性
3. 降低程序的耦合度
没有使用接口
使用接口
这段代码的作用就是,我跟你要一个接口(第7行),然后我使用这个接口(第11行,就是调用接口里的方法)
定义的接口只是一个约定,告诉你这个接口有吃,说话的功能,而接口的子类,实现这个约定,在main方法里,创建接口类的子类对象,在调用接口时,你必须把根据约定做好的东西(子类)给我,我才能使用这个接口的功能l.on()
实现了多继承
19. 匿名内部类
匿名内部类
一般用在只想用一次,以后就不用了
内部类
如果只想在一小段范围内使用几次,使用内部类
public class Test {
public static void main(String[] args) {
/**
* 内部类,如果只想在一小段范围内使用几次,使用内部类
* @author 最帅的我
*
*/
class Xixi implements MyInterface{
public void eat() {
System.out.println("这是一个内部类");
}
@Override
public void say() {
System.out.println("而且有名字");
}
}
/**
* 匿名内部类,用在只想调用一次,以后就不用了
*/
MyInterface m1 = new MyInterface() {
@Override
public void eat() {
System.out.println("这是一个匿名的内部类");
}
@Override
public void say() {
System.out.println("一次性");
}
};
//使用匿名内部类
m1.eat();
m1.say();
//使用有名字的内部类
MyInterface m2= new Xixi();
m2.eat();
m2.say();
}
20. 包装类
java.lang包下为8种基本数据类型提供对应的包装类
8中基本数据类型以及对应的包装类
包装类作用
包装类提供了字符串、基本数据类型和包装类相互转化的方法
数字基本数据类型的包装类都继承了Number类,它们的使用方式相似,下面以常用的基本数据类型int对应的包装类Integer为例说明数字类型包装类的使用
1. 基本数据类型 int值转化为Integer类型对象
int i = 20;
Integer integer1 = new Integer(i);//方法一
Integer integer2 = Integer.valueOf(i);//方法二
2. Integer对象转化为基本数据类型int值
Integer integer = new Integer(20);
int i1 = integer.intValue();
3. String类型的数字转化为Integer对象
String s = “120”;
Integer integer1 = new Integer(s);//方法一
Integer integer2 = Integer.valueOf(s);//方法二
4. Integer类型转化为String类型
Integer integer = new Integer(20);
String s1 = integer.toString();
5. String类型的数字转化为基本数据类型的int值
String s = “120”;
int i1 = Integer.parseInt(s);//方法一
Integer integer = new Integer(s);
int i2 = Integer.intValue();//方法二
6. 基本数据类型int转化为字符串
int i1 = 20;
String str = String.valueOf(i1);//方法一
str = Integer.toString(i2);//方法二
boolean类型的包装类Boolean:Boolean用于将一个基本数据类型boolean值包装为对象
1. 将boolean值转换为Boolean对象
Boolean b1 = new Boolean(true);//方法一
Boolean b2 = Boolean.valueOf(true);//方法二
2. 将Boolean对象转换为boolean值
Boolean b = new Boolean(true);
boolean b1 = b.booleanValue();//方法一
Integer的equals方法
1. Integer的equals方法继承自Object,并且进行了重写
2. Integer的equals方法只有一种情况返回true:两个Integer类型的对象 i1 和 i2包含的值相等时;其他情况返回false
比如:
Integer i1 = new Integer(20);
Integer i2 = new Integer(30);
Integer i3 = new Integer(20);
boolean b = i1.equals(i2);//false
b = i1.equals(i3);//true
包装类中的toString方法重写过
不是什么类型数据都可以转换为包装类,比如布尔型数据类型转换为整型包装类是不可以的,必须同类型包装。
1. 特殊情况,整型数据转为长整型数据,这是可以的,下面代码中虽然括号中要求填长整型数据,但是java中默认将整型数据转换为长整型数据,小可以转大,大不可以转小。
int m =335;
Long l = Long.valueOf(m);
再说包装类
1. 字符串转doubel,第一种方法Double包装类中有一个parseDouble方法可以将字符串转为Double包装类,该方法会返回Double包装类数据,同类型包装之间默认自动转换(其他类似)。
//字符串转double
String s1 = "12.3456";
Double d1 = Double.parseDouble(s1);
Double d2 = Double.valueOf(s1);
Double d3 = new Double(s1);
double d4 = d1;
System.out.println(d4);
//double转字符串
double d5 = 3.14159;
String d6 = Double.valueOf(d5).toString();
String d7 = Double.toString(d5);
String d8 = new Double(d5).toString();
String d9 = "" + d5;
System.out.println(d6);