------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
2.1 面向对象概念
2.1.1 理解面向对象
所谓面向对象(Java)是相对于面向过程(C)而言,这两个都是一种编程思想,面向过程强调的是功能行为,而面向对象是将功能封装进对象,强调具备了功能的对象。
面向对象是基于面向过程的。
面向对象设计把握一个重要的经验:谁拥有数据,谁就对外提供操作这些数据的方法。—— 张孝祥
2.1.2 面向对象思想的特点
1. 是一种符合人们思考习惯的思想
2. 可以将复杂的事情简单化
3. 将程序员从执行者转换成了指挥者
4. 完成需求时:
(1) 先要去找具有所需的功能的对象来用。
(2) 如果该对象不存在,那么创建一个具有所需功能的对象。
(3) 这样简化开发并提高复用。
2.1.3 面向对象开发、设计、特征
1.开发过程:其实就是不断的创建对象,使用对象,指挥对象做事情。
2.设计的过程:其实就是在管理和维护对象之间的关系。
3.面向对象的特征:封装、继承、多态。
2.2 类与对象的关系
2.2.1 类与对象
使用计算机语言就是不断的在描述现实生活中的事物。Java中事物通过类的形式体现,类是具体事物的抽象、概念上的定义。对象即使该类事物实实在在的个体。如:人就是一个类,而每一个具体的人就是对象(有各自的年龄、姓名等属性,有吃、喝、跑说话等功能)
2.2.2 类的定义
生活中对事物的描述一般会对事物的属性和行为进行描述,Java中用类class也是通过属性(对应类中的成员变量)、行为(对应类中的成员函数)来描述事物。定义类其实就是在定义类中的成员(成员变量和成员函数)。
定义:Java语言的最小编程单位,是一组事物共有的特征和功能的描述,它是对于一组事物的总体描述。
2.3.3 成员变量和局部变量的区别
成员变量:
(1) 成员变量定义在类中,整个类中都可以被访问。
(2) 成员变量随着对象的建立而建立,存在于对象所在的对内存中。
(3) 成员变量有默认初始化值。
局部变量:
(1) 局部变量只定义在局部范围内,如:函数内,语句内等。
(2) 局部变量存在于栈内存中。
(3) 作用的范围结束,变量空间会自动释放。
(4) 局部变量没有默认初始化值。
注意:如果在一个类的某个成员方法中定义了一个与成员变量同名的局部变量,该方法会对局部变量进行访问,而不在访问成员变量。因为局部变量存在栈里,而成员变量存在堆里。
2.2.4 创建对象,使用对象
声明格式: 构造方法 对象名 = new 构造方法(参数);
实例:
class Car { //对Car这类事物进行描述
String color = "red";
int num = 4;
void show() {
System.out.println("color="+color+"..num="+num);
}
}
class CarDemo {
public static void main(String[] args) {
Car c = new Car(); //建立对象
c.color = "black"; //对对象的属性进行修改
c.show(); //使用对象的功能。
}
}
2.2.5 对象内存结构
只要是用new操作符定义的实体就会在对内存中开辟一个新的空间,并每一个对象中都有一份属于自己的属性,通过对象.对象成员的方式操作对象中的成员,对其中一个的成员进行了修改,和另一个对象没有关系。
2.2.6 创建对象的步骤
Person p = new Person(); //到底在内存中做了什么?
有了构造代码块程序执行顺序和源码顺序也有关系
(1) 将Person.class文件加载进内存。
(2) p定义函数中,那么在栈内存中开辟一个变量空间p。
(3) 在堆内存中给对象分配空间,并分配内存地址值
(4) 给对象中的属性进行默认初始化。
(5) 给对象中的属性进行显示初始化。
(6) 调用构造代码块对对象进行初始化。(执行类中的构造代码块,和5与原码顺序有关)
(7) 调用对应的构造方法进行对象初始化。对象初始化完毕。
(8) 将对象内存地址赋值给p变量。让p变量指向该对象。
注意:当类被实例化为对象时,Java虚拟机会对类的成员变量自动初始化赋值,针对不同的数据类型,Java虚拟机会赋不同的值。
2.2.7 匿名对象
概念:匿名对象是对象的简化形式,顾名思义就是没有引用名字的对象。
使用情况:
(1) 对对象方法仅进行一次调用时。
(2) 匿名对象可以作为实际参数进行传递。
实例:定义方法(汽车改装厂),匿名对象作为参数。
实例 1::new Person(); 匿名对象只能使用一次,它可以访问类的所有成员,如同过:new Person().speak();
实例 2:
class CarDemo2 {
public static void main(String[] args) {
/*new Car().num = 4;
new Car().color = "red";*/
//new Car().run();
/*Car c1 = new Car();
c1.num = 10;
c1.color = "blue";
Car c2 = new Car();
c2.num = 10;
c2.color = "blue";代码复用性太差*/
//Car c1 = new Car();
method(new Car());
method(new Car());
method(new Car());
method(new Car());
method(new Car());
method(new Car());
method(new Car());
method(new Car());
}
public static void method(Car c) { //Car c = new Car();
c.num = 10;
c.color = "blue";
c.run();
}
}
class Car{
int num;
String color;
public void run() {
System.out.println(num + ".........." + color);
}
}
可以调用类的成员方法。如果在程序中再写一次new Person(),在内存中就创建了两个匿名对象,这两个匿名对象存在于不同的内存空间。
2.2.8 对象的生命周期
当使用new关键字创建一个对象时,对象的生命周期就开始了,当没有人呢和引用变量指向这个对象时,这个对象成为垃圾,不能在被使用,这个对象的声声明周期就结束了。(① 离开{};② p = null)
2.3 封装
2.3.1 封装的概念
是指隐藏对象的属性和实现细节,仅对外提供公共访问方式,封装是相
对的,不是绝对的。
2.3.2 封装的作用
好处:①将变化隔离 ②便于使用 ③提高重用性 ④提高安全性
2.3.3 封装的原则
(1) 将不需要对外提供的内容都隐藏起来。
(2) 把属性都隐藏,提供公共方法对其访问。
2.4 构造方法
2.4.1 构造方法的特点
(1) 函数名与类名相同
(2) 不用定义返回值类型
(3) 不可以写return语句
(4) 构造方法不由编程人员调用,由系统调用。
2.4.2 构造方法的作用
给对象进行初始化。构造方法的主要作用是完成对象的初始化工作,它能够把定义对象时的参数传给对象的域。
2.4.3 构造方法应注意
(1) 构造函数细节:如果在定义类时没有定义构造方法,则编译系统会自动插入一个无参数的默认构造器,这个构造器不执行任何代码。
(2) 多个构造方法是以重载的形式存在的,如果设置了有参数值的构造方法,系统则不会在默认定义一个默认构造器,所以最好再定义一个无参数值的构造方法,以便于调用类中的方法。
2.3.4 构造方法和一般方法的区别
从功能上的区别:
(1) 构造方法是给对象初始化的。
(2) 一般方法是因为对象需要满足某种功能定义的。
从执行上的区别:
(1) 构造方法,是对象创建的时候被执行,不用调用。
(2) 一般方法是什么时候调用就什么时候执行,不调用就永远不执行。
2.3.5 构造方法和setXxx区别:
(1) 如果你只是为了创建对象并给对象进行初始化的话,用有参的构造函数
(2) 如果你是为了对原来的属性值不满意,想修改,用setXxx,因为是在原对象的基础上对属性改值,不用再创建对象
2.5 局部代码块和构造代码块
2.5.1局部代码块
例如:
public void method(){
{
int x = 4;
System.out.println("x="+x);
}
}
作用:定义在方法中,可以限定变量的生命周期.(不常见,面试。)
2.5.2构造代码块
例如:
{
System.out.println("我是初始化块")
}
作用:定义在类中,可以提高初始化块的复用,提高整个应用的可维护性,是对构造器的一种补充。
说明:
(1) 括号里的是初始化块,这里面的代码在创建java对象时执行,而且在构造器之前执行!(构造器其实就是构造方法)
(2) 其实初始化块就是构造器的补充,初始化代码块是不能接收任何参数的,定义的一些所有对象共有的属性、方法等内容时就可以用初始化块了初始化!!
2.5.3构造代码块实例
class PersonDemo2 {
public static void main(String[] args) {
/*System.out.println("你好局部代码块");
{
int x = 10;
System.out.println(x);
}*/
Person p = new Person();
Person p1 = new Person("干露露");
Person p2 = new Person();
}
}
class Person{
String name;
Person() {
System.out.println("我是空参数的");
}
Person(String name) {
System.out.println("我的名字是" + name);
}
/*
构造代码块每创建一次对象就执行一次
*/
2.6 private(私有)关键字
2.6.1 private关键字概述
是一个权限修饰符,用于修饰成员(成员变量和成员函数),被私有化的成员只在本类中有效,当成员私有后,提高了安全性。但是访问权限降低了。
2.6.2 private关键字作用
可以在方法中对成员变量的访问进行控制。
2.6.3 使用注意
(1) private可以修饰内部类,不能修饰外部类;
(2) 私有仅仅是封装的一种体现形式而已;
2.6.4 使用方式
将成员私有化,对外提供对应的set ,get方法对其进行访问。提高对数据访问的安全性
将构造函数私有化,则其余类无法对新建对象初始化,只可以通过类名来调用(静态)。
实例:
2.7 this关键字
2.7.1 this关键词概述
Java关键字this只能用于方法体内。当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配一个引用自身的指针,这个指针的名字就是this。因此,this只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现this,(这在讲解Java关键字static、final中给出了明确解释。)并且this只和特定的对象关联,而不和类关联,同一个类的不同对象有不同的this。
2.7.2 this关键词特点
this代表其所在函数所属对象的引用,也就是this代本类对象的引用。简言之,哪个对象调用this所在的函数,this就代表哪个对象。
2.7.3 什么时候使用this关键字
(1) 引用成员变量:函数参数或者函数中的局部变量和成员变量同名的情况下,成员变量被屏蔽,此时要访问成员变量则需要用“this.成员变量名”的方式来引用成员变量。当然,在没有同名的情况下,可以直接用成员变量的名字,而不用this,用了也不为错.
(2) 代表自身对象:在函数中,需要引用该函数所属类的当前对象时候,直接用this。//比较两个人的年龄
(3) 引用构造方法:注意,如果我们想在一个构造函数中对另一个构造函数进行调用的时候,不能在其构造函数中直接类名(参数)这样调用,而是通过this调用另一个构造方法,用法是this(参数列表),这个仅仅在类的构造方法中,别的地方不能这么用。这叫this语句.只能放在构造函数的第一行
其实这些用法总结都是从对“this是指向对象本身的一个指针”这句话的更深入的理解而来的,死记不靠谱,容易忘记,而且容易搞错,要理解!
2.7.4 this关键字使用实例一
class ThisDemo {
public static void main(String[] args) {
Person p1 = new Person("张三",20);
}
}
class Person{
private String name;
private int age;
Person() {
}
Person(String name,int age) {
this.name = name;
this.age = age;
}
}
2.7.5 this关键字使用实例二
class ThisDemo2 {
public static void main(String[] args) {
/*Person p1 = new Person(30);
Person p2 = new Person(30);
System.out.println(p1.compare(p2));*/
Person p1 = new Person("李四");
}
}
class Person{
private int age;
private String name;
Person(int age) {
this.age = age;
System.out.println(this.age);
}
Person(String name) {//name = "李四"
this();
this.name = name;
System.out.println(this.name);
}
Person() {
this(20);//可以调用本类的其他的构造函数,通过传参数来指定调用哪个构造函数
System.out.println("我是空参的构造函数");
}
public boolean compare(Person pp) {
if (this.age == pp.age) {
return true;
}
return false;
}
}
2.8 static关键字
2.8.1 方法区
各个线程所共享的内存区域,它用于存储已被虚拟机加载的类信息.常量、静态变量、即时编译器编译后的代码等数据。虽然java虚拟机把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来.
3.8.2 static关键字作用
用于修饰成员(成员变量和成员方法),起到数据共享的作用。
(1) 当每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用。
(2) 一个类里所有的方法都定义成静态后,可以方便于使用,但是该类还是可以被其他程序建立对象。
为了更严谨,强制让该类不能建立对象,可以通过将构造函数私有化完成(private)
2.8.3 被修饰后的成员具备以下特点
(1) 随着类的加载而加载。也就是说:静态会随着类的消失而消失,说明它生命周期最长。
(2) 优先于对象存在。明确一点:静态先存在,对象后存在。
(3) 被所有对象所共享
(4) 可以直接被类名调用,格式: 类名.静态成员
(5) 静态修饰的数据是共享数据,对象中存储的是特有数据。
2.8.4 什么时候使用静态
1. 静态变量。
当分析对象中所具备的成员变量的值都是相同的 ,这时这个成员就可以被静态修饰。
只要数据在对象中都是不同的,就是对象的特有数据,必须存储在对象中,是非静态的。
如果是相同的数据,对象不需要做修改,只需要使用即可,不需要存储在对象中,定义成静态的。
实例:
class StaticDemo2 {
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "焦裕禄";
Person p2 = new Person();
p2.name = "孔繁森";
p1.speak();
p2.speak();
}
}
class Person{
String name;
static String country = "中国";
public void speak() {
System.out.println("我的名字是" +name +"我的国籍是" + country);
}
}
2. 静态函数
函数是否用静态修饰,就参考一点,就是该函数功能是否有访问到对象中的特有数据。
简单点说,从源代码看,该功能是否需要访问非静态的成员变量,如果需要,该功能就是非静态的。否则可以定义为静态或者定义为非静态。(不访问非静态就能用)。
但是非静态需要被对象调用,而仅创建对象调用非静态的,却没有访问特有数据的方法,该对象的创建是没有意义。(也就是说:如果为了调用一个静态变量专门创建一个对象而不访问实例变量,这样做是没有意义的。)
静态函数一般都是类内部独立的功能方法,其作用实就是为了便于方法的调用,比如API中很多的方法都是写成静态的。
注意:静态方法是类内部的一类特殊方法,只有在需要时才将对应的方法声明成静态的,一个类内部的方法一般都是非静态的。
2.8.5 实例变量(非静态的成员变量)和类变量(静态变量)的区别
存在位置:
(1) (类变量)静态变量随着类的加载而存在于方法区(共享数据区)的静态区,
所以也叫对象的共享数据。
(2) 实例变量随着对象的建立而存在于堆内存中。
生命周期:
(1) 静态变量的生命周期最长,随着类的消失而消失。
(2) 实例变量的生命周期随着对象的消失而消失。
所属不同:
(1) 静态变量也称之为类变量,所属于整个类,被整个类所共享。
(2) 实例变量是对象的特有数据,所属于对象。
别名不同
(1) 成员变量也称为实例变量。
(2) 静态变量称为类变量。
举例:定义一个非静态的属性,和一个静态属性,再定义一个静态方法和非静态方法对属性进行输出并画内存图演示
实例:
class StaticDemo3 {
public static void main(String[] args) {
/*Demo d = new Demo();
d.print();*/
Demo.method();
}
}
class Demo{
int num1 = 10;
static int num2 = 20;
public void print() {
int num3 = 30;
//System.out.println(num1);
System.out.println(num3);
}
//静态方法在访问的时候是有局限性的
public static void method() {
System.out.println(num2);
}
}
2.8.6 静态方法使用注意事项
(1) 静态方法只能访问静态成员(非静态方法中不可以定义静态变量)
(2) 静态方法中不可以写this,super关键字(因为静态变量优先于对象存在)
(3) 主函数是静态的。
2.8.7 静态的利弊端
利处:
(1) 对对象的共享数据尽享单独空间的存储,节省空间,没有必要没一个对象都存储一份。
(2) 可以直接被类名调用。
弊端:
(1) 生命周期过长。
(2) 访问出现局限性。(静态虽好,但只能访问静态)
2.8.8 静态代码块和程序初始化
2.8.8.1 静态代码块格式及特点
格式:
static{
静态代码块中的执行语句
}
特点:
随着类的加载而加载,且只执行一次无需调用,并优先于主函数,起到对类进行初始化的作用。
2.8.8.2 小结:局部代码块&构造代码块&静态代码块
1. 局部代码块:
作用:控制变量的生命周期;
在程序中,当我们已经使用完 x 后,并且在接下来的代码中,不会再用到x,那么就没必要让x 在内存中占用空间了,这用情况下,可以使用 局部代码块,将x及其所设计到的区域封装为局部代码块,他们在程序执行中顺序不变,只是在执行完成后消失。
2. 构造代码块:
作用:它可以给所有对象进行初始化
存在于:类中。
当类中的构造方法以重载的形式存在时,并且有共同成员变量或共同的方法时,可以通过构造代码块对其进行初始化;这样可以减少代码的重复!
3. 静态代码块:
作用:给类进行初始化。
当类中的方法都被静态了化,并且构造方法被private了,这时我们不能,在将这个类实例化,然而又想让类增加一些属性,就可以使用静态代码块
注意:类中加载顺序 静态代码块--构造代码块--构造方法
2.9主函数
2.9.1 主函数定义
是一个特殊的函数,作为程序入口,可以被jvm调用。
2.9.2 主函数涵义
public: 代表着该函数的访问权限是最大的。
static: 代表主函数随着类的加载就已经存在了。
void: 主函数没有具体的返回值。
main:不是关键字,但是是一个特殊的单词,可以被jvm识别。
(String[] args):函数的参数,参数类型是一个数组,该数组的元素是字符串。字符串类型数组。(arguments)
2.9.3 注意
主函数是固定格式的 ,被jvm识别。(除args以外不能改动)。
2.9.4 主函数中的字符串数组
class Demo {
public static void main(String[] args) {
System.out.println(args[0]);
System.out.println(args.length);
//通过两个输出语句可以验证,jvm给主函数传递的实际参数是:new String[0];
//也就是jvm再调用主函数的时候传递了空的字符串的数组
//大家想一想如果我们想给其传值怎么传呢?
}
}
2.10 文档注释
1. javadoc -d(指定文档存储的位置如果写.代表当前目录,也可以定义一个文件夹)
2. -author(提取作者内容)
3. -version(提取版本内容)
4. javadoc -d 指定的文件目录 -author -version ArrayTool.java
5. @param 参数名称//形式参数的变量名称@return 函数运行完返回的数据
说明:private和构造函数不会出现在生成API的方法中。
2.10单例设计模式
2.10.1 设计模式概念
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。
说明:“四人帮”搞出了23种基本设计模式,但新的模式不断出现。
2.10.2 单例设计模式概念
单例设计模式就是保证类只有一个对象
2.10.3 单例设计模式的作用
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要
2.10.4 单例设计模式的实现
整体思路:
让类自身负责保存它的唯一实例。并且它可以提供一个访问该实例的方法。
步骤:
(1) 控制类的创建,(private构造函数)不让其他类来创建本类的对象。
(2) 在本类中定义一个本类的对象。Single s;
(3) 提供公共的访问方式。 public static Single getInstance(){return s}
2.10.4.1 方式一:饿汉式
思路:在本类中定义好对象,坐等调用。
class Test1 {
public static void main(String[] args) {
System.out.println(Single.getS());
// 验证静态方法可以用类名.方法的方式调用
Single b = Single.getInstance();
// 获取单例
System.out.println(b.getS());
// 验证单例获取成功
}
}
class Single{
private static String s = "我是成员变量的内容" ;
private Single(){
}
// 将构造函数定义为私有,不允许其它类创建对象(无法初始化)。
private static Single a = new Single();
// 在本类创建一个对象
public static Single getInstance() {
return a;
}
//定义对象的获取方法
public static String getS() {
return s;
}
// 定义成员变量的获取方法
}
2.10.4.1 方式二:懒汉式(面试用、有安全隐患)
思路:不调用不创建对象,调用的时候在创建。
class Test2 {
public static void main(String[] args) {
System.out.println(Single.getS());
// 验证静态方法可以用类名.方法的方式调用,而不经过对象。
Single b = Single.getInstance();
// 获取单例
System.out.println(b.getS());
// 验证单例获取成功
}
}
class Single {
private static String s = "我是被私有化的成员变量";
private static Single a = null ;
//声明一个对象但不在堆中创建。
private Single (){}
//私有化构造函数,使别的类无法调用本类初始化对象。
public static Single getInstance() {
if (a == null) {
a = new Single();
}
//判断是否已经有了对象,没有就创建,有就执行下面的返回
return a;
}
public static String getS(){
return s;
}
}