Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

时间:2023-02-16 23:22:59

一. 面向对象概念:

面向对象其实是一种思考的思想,早期思想是面向过程。
面向过程注重的是过程,过程所涉及的行为,也就是功能。

【实例】:面向过程: 1. 把冰箱打开 2. 把大象放入 3. 冰箱关起来
     面向对象: 打开冰箱,储存,关闭都是对冰箱的操作,是冰箱的行为。冰箱就是一个对象,所以只要操作冰箱所具备的功能,都要定义在冰箱中。

Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

【总结】: 所属在冰箱中,先看到冰箱,有了冰箱就有了这些功能,把这些功能封装在冰箱中。
      先找到这些功能有哪些特性,所属于什么事物,找到事物,把功能全封装进去。

【面向对象概念】

  1. 面向对象是思考问题的一种思考方式,是一种思想。
  2. 面向对象的好处:将复杂的事情变简单了,只要面对一个对象就行。

【面向对象设计】

面向对象设计把握一个重要的经验:谁拥有数据,谁对外提供操作这些数据(私有)的方法!
(被动的一方是数据的拥有者,主动的一方是执行者)

【实例 1】:人在黑板上画园:
     => 对象:person, blackboard, circle

draw() //画圆
{
(x, y) //圆心
radius //半径
}

/*圆心和半径是circle内部的数据,画圆的方法要操作圆心和半径
所以画圆的方法是圆提供的。
*/



【实例 2】:列车司机紧急刹车
     => 对象:司机, 列车
     => 刹车的动作:列车身上的方法


【实例 3】:售票员统计收获小票的金额
     => 对象:售票员, 小票
     => 统计收获小票的金额的方法:是小票身上的方法。
      因为商品的价格是在小票内部的数据,售票员只是调用小票的getTotalMoney( )


【实例 4】:你把门关上了:[ 名称提炼法 ]
     => 对象:门, 人
     => 关门的方法:是门身上的方法,人只是调用门的closeDoor( )

closeDoor() //关门
{
//旋转; 装到门框; 伸出锁舌; 插到锁孔;
}



【实例 5】:路上有很多汽车,路上还随时可以增加,减少汽车:
     => 对象:路, 汽车
     => 增加,减少汽车的方法:是路身上的方法,不是汽车自己冲过去的。


【实例 6】:球从一根绳子的一端移动到了另一端:
     => 对象:球, 绳子
     => 绳子:为球的移动指引了方向 nextPoint( )
      球:move( )

class Rope
{
private Point start;
private Point end;
public Rope(Point start, Point end)
{
this.start = start;
this.end = end;
}

public Point nextPoint(Point currentPoint)
{
/*通过两点一线的数学公式可以计算出当前点的下一个点
* 如果当前点是终点,则返回null;
* 如果当前点不是线上的点,则抛异常。
* */

}
}

class Ball
{
private Rope rope;
private Point currentPoint;
public Ball(Rope rope, Point currentPoint)
{
this.rope = rope;
this.currentPoint = currentPoint;
}


public void move() //设置为定时器,每隔1秒move一次
{
currentPoint = rope.nextPoint(currentPoint);
System.out.println("小球移动到了" + currentPoint);
}
}



【实例 7】:两块石头磨成一把石刀,石刀可以砍树,砍成木材,木材可以做成椅子:
     => 对象:stone  (自己变成石刀,自己都没有了,所以不是自己的方法)
         stoneknife => stoneKnife = KnifeFactory . createKnife( Stone first, Stone second )
         tree
         material  => material = stoneKnife . cut( tree )
         chair    => chair = ChairFactory . createChair( material )

【面向对象的三个特征】

面向对象的三个特征:封装,继承,多态。

开发时:找对象,建对象,用对象,并维护对象之间的关系。

二. 类与对象的关系:

1. 类与对象的关系

  1. 类就是对现实生活中事物的描述。
  2. 对象就是这类事物,实实在在的个体。
【分析】:张三,李四 【映射到内存中】:
现实生活中的对象:张三,李四。

对象:在Java中用new操作符所产生的一个实体,这个实体在堆内存中。

一个实体(具体对象)
想要描述:提取对象*性内容,对具体的抽象

描述时,这些对象的共性有:姓名,年龄,性别,学习Java的能力。
一个类(class定义的类)


【实例】:需要描述汽车,描述事物 其实就是描述事物的属性行为

  1. 【描述事物】:定义类
  2. 【属性和行为】:类中的成员(成员变量,成员函数)
  3. 【属性】:类中的变量
  4. 【行为】:类中的函数

Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

public class CarDemo {

public static void main(String[] args) {
//生产汽车,在Java中通过new操作符来完成,其实就是在堆内存中产生一个实体。‘

Car c = new Car();
//c 是引用类型变量,就是类类型变量,指向对象,即指向该类产生的实体。
}

}

class Car
{
String color = "red"; //描述颜色
int num = 4; //描述轮胎数

/**
* 运行行为
*/

public void run()
{
System.out.println(color + "..." + num);
}
}

2. 对象的内存分配

【实例 1】对象的内存分配情况一。

Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

【分析】:

  1. [ new Car( ) ]:新建一个实体。
  2. 堆内存中的变量都有一个特点:默认初始化值。
    如果c.color没有显示初始化值,它的默认初始化值为null(因为字符串默认初始化值为null)。

【实例 2】对象的内存分配情况二。

Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

【分析】:

  1. [ Car c1 = c ] :叫多引用指向同一对象
  2. [ c1.run( ) ]:结果为 color = “green”;  num = 5;
【总结】:
1. 对象的特点:用于封装数据(属性,行为)

2. 类不独立运行可以没有主函数,在主函数中建立类的对象,可以调用该类中的属性方法。

3. 【成员变量与局部变量的区别】: (1)作用不一样: 成员变量:作用于整个类
局部变量:作用于函数中,或者语句中

(2)在内存中的位置: 成员变量:在堆内存中,因为对象存在才在内存中存在。
局部变量:存在栈内存中


class Car
{
String color = "red"; //描述颜色
int num = 4; //描述轮胎数 【?】

/**
* 运行行为
*/

public void run()
{
System.out.println(color + "..." + num); //成员变量作用在整个类中,可以直接访问。
}

/**
* 在本类中创建本类对象
*/

public static void main(String[] args)
{
Car c = new Car();
c.num = 10; //这个变了,但是【?】处没变,相当于car变了,图纸没变。
}
}

3. 匿名对象

对象可以起名字,也可以不起名字。匿名对象是对象的简写形式。

【匿名对象的使用方式】:
【方式 1】 (1)当对象的方法只调用一次时,可以用匿名对象来完成,这样写比较简化。

【实例】:

   Car c = new Car( );
   c.num = 5;

 => new Car( ).num = 5;

(2)如果对一个对象进行多个成员调用,必须给这个对象起名字。

【实例】:内存泄露
Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)
【方式 2】 匿名对象可以作为实际参数进行传递。


【实例】:汽车修配厂,对汽车进行改装,将来的汽车都改成黑色,三个轮胎。

1. [ 法一 ]:没有采用匿名对象。
Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

【分析】:show 运行结束完,对象c 还被main引用,当mian结束才变为垃圾。要提前变为垃圾:c = null;

2. [ 法二 ]:采用匿名对象。
Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

【分析】:

 (1)[ show( Car c){ } ]:相当于Car c = new Car( ); 堆内存中的new Car( )不是垃圾,被show中的c 引用。

 (2)当show运行结束后,show为垃圾,实际参数的匿名对象没有引用,也变为垃圾。


三. 封装:

封装是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

【封装体】: 函数就是最小的封装体,类也是封装体,包,框架(用于组件的开发)等。
【好处】: 将变量隔离,便于使用,提供重用性,提高安全性。
【原则】: 将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共方法对其访问。
【private】: 私有,权限修饰符:用于修饰类中的成员(成员变量, 成员函数),私有只有在本类中有效。


【实例 1】:将年龄私有化

public class Demo {

public static void main(String[] args) {
Person p = new Person();
// p.age = -20; //访问不到
p.speak();

}
}
class Person
{
private int age;

public void speak()
{
System.out.println("age=" + age);
}
}

【实例 2】:将age私有化以后,类以外即使建立对象也不能直接访问,但是人应该有年龄,就需要在Person类中提供对应访问age的方法。

  1. set返回值类型肯定是void,只设置不需要返回值,带参数。
  2. get没有参数,只获取,而且get的返回值类型和获取的变量一样。
  3. 一个类里面在setXXX,getXXX功能,代表这个类里边一定有一个私有的属性XXX。
public class Demo {

public static void main(String[] args) {
Person p = new Person();
p.setAge(20);
p.speak();

}
}
class Person
{
private int age; //一个成员变量,通常会对应两个访问方式,一个叫set设置,一个叫get获取。

public int getAge() {
return age;
}

/*两个访问方式,之所以对外提供访问方式,就是因为可以在访问方式中加入逻辑判断等语句,
对访问的数据进行操作,提高代码健壮性。
*/

public void setAge(int age) {
if(age > 0 && age < 120)
{
this.age = age;
}
}

public void speak()
{
System.out.println("age=" + age);
}
}


Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

【注意】:封装不是私有,私有仅仅是封装的一种表现形式,不私有也可以实现封装,只要权限在访问不到的范围内是封装的。
     私有权限是最小的权限。

类中有多少属性,一般都需要隐藏起来。

四. 构造函数:

1. 构造函数

构造函数可以重载。
【特点】: 1. 函数名与类名相同。
2. 不用定义返回值类型(与void不同,void是一种返回值类型,代表没有具体结果返回的情况)
3. 不可以写return语句,系统也不会加。


public class Demo {

public static void main(String[] args) {
Person p = new Person(); //[1]
}
}

class Person
{
public Person() //[2]
{
System.out.println("Person");
}
}
/*
输出结果:Person
[1]和[2]处是一样的。
所以对象一建立,就会调用与之对应的构造函数,new一个就调用一次。
*/

【构造函数的作用】: 可以给对象进行初始化,也就是说当在堆内存中产生对象的时候,这个对象需要一个初始化动作。
【对象为什么要初始化】: 现实生活中的事物很多,它只要一出现,就具备基本的特性,
比如,产生一个人,他一出生就会哭,哭是人一出生的行为。
【构造函数的小细节】: 当一个类中没有定义构造函数时,那么系统会默认给改类加入一个空参数的构造函数:Person(){ };
加一个后,方便该类初始化,否则对象创建不出来。
在类中自定义了构造函数后,默认的构造函数就没有了。


【实例 1】:一个类能产生对个对象,而这些对象都可以去调用不同的初始化方式。

public class Demo {

public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person("lisi");
Person p3 = new Person("wangwu", 10);

}
}

class Person
{
private String name;
private int age;

/*自定义了构造函数后,没有手动设置空参数的构造函数初始化,new Person()是不可以创建对象的。*/
public Person()
{
System.out.println("A: name=" + name + ", age=" + age);
}
public Person(String name)
{
this.name = name;
System.out.println("B: name=" + name + ", age=" + age);
}
public Person(String name, int age)
{
this.name = name;
this.age = age;
System.out.println("C: name=" + name + ", age=" + age);
}
}

【实例 2】:构造函数和一般函数的区别

public class Demo {

public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person("lisi");
Person p3 = new Person("wangwu", 10);
p1.setAge(10); //一般函数,被对象调用。
}
}
【构造函数和一般函数的区别】:
1. 构造函数和一般函数在写法上有不同
2. 运行上有不同 构造函数:是在对象一建立就运行,给对象初始化。
一般函数:是对象调用才执行,给对象添加对象具备的功能。

3. 运行次数不同 构造函数:一个对象建立,构造函数只运行一次。
一般函数:可以被对象调用多次。

【什么时候定义构造函数?】:
当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容定义在构造函数中,
构造函数在定义时,需不需要未知内容参与运算,需要就定义参数,和函数一样。

【构造函数 + private】:
构造函数是可以被私有化的,因为私有化是来修饰成员的,构造函数也是成员,把构造函数私有化,代表这个类是不可能创建对象的,因为对象都不能进行初始化动作。


2. 构造代码块

构造代码块:定义不同对象共性初始化内容。

【作用】: 给对象进行初始化,对象一建立就运行,而且优先于构造函数执行。

【构造代码块与构造函数区别】: 构造代码块:是给所有对象进行统一初始化
构造函数:是给对应的对象初始化。


public class Demo {

public static void main(String[] args) {
Person p = new Person();
}
}
class Person
{
private String name;
private int age;

{
System.out.println("构造代码块");
}

public Person()
{
System.out.println("name=" + name + ", age=" + age);
}
}

/*【运行结果】:
构造代码块
name=null, age=0
*/

五. this关键字:

【第一点】: this:看上去是用于区*部变量和成员变量同名情况。

【1. this为什么可以解决这个问题? 2. this到底代表的是什么?】

=> this就代表本类的对象,this代表它所在函数所属对象的引用。


【实例 1】:同名局部变量和成员变量用this

public class Demo {

public static void main(String[] args) {
Person p = new Person("张三");
}
}
class Person
{
private String name;

public Person(String name)
{
this.name = name; //局部中有name,在局部中找name使用,局部中没有,就找成员用。
}
}
/* this.name = name; main 中 Person p = new Person("张三");此处的this就是p对象。
简单说,哪个对象在调用this所在函数,this就代表哪个对象。
*/

【实例 2】:this省略情况

class Person
{
private String name;
private int age;

public void speak()
{
System.out.println("name=" + this.name + ", age=" + this.age);
//此处this可以省略,但变量出现同名情况,就一定要加。
}
}
/*在一个类中,成员之前相互调用,其实都是对象完成的,而本类中调用this,运行的对象,才是被this表示的对象。*/


【第二点】: this:只能用在构造函数间,一般函数不能用。

【this 的应用】:

(1)当定义类中功能时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象。
   但凡本类功能内部使用了本类对象都用this表示。[ 见实例 1 ]

(2)this 语句:用于构造函数之间的相互调用,用时要传相对应的参数。[ 见实例 2 ]


【实例 1】:给人定义一个用于比较年龄是否相同的功能,也就是是否是同龄人。

class Person
{
private int age;

public Person(int age)
{
this.age = age;
}

/**
* 比较两人年龄是否相同
* @param p 传递对象
* @return 返回boolean值
*/

public boolean compare(Person p)
{
return this.age == p.age;
}
}

public class Demo {

public static void main(String[] args) {
Person p1 = new Person(10);
Person p2 = new Person(20);
System.out.println(p1.compare(p2)); //p1 和 this是引用对象指向同一对象
}
}

【实例 2】:构造函数之间的相互调用

class Person
{
private String name;
private int age;

public Person(String name)
{
this.name = name;
}

public Person(String name, int age)
{
this(name); //this代表对象,=>p(name) =>new Person(name);给某个对象进行另外的初始化,操作统一对象。
this.age = age;
}
}

public class Demo {

public static void main(String[] args) {
Person p = new Person("lisi", 20);
}
}


【第三点】: this:只能定义在构造函数的第一行。(初始化动作要先做)


【实例 1】:this定义在构造函数第一行。

class Person
{
private String name;
/* 一个类中有很多种初始化方式,内部初始化方式可以私有起来,只对外暴露一个。*/
private Person()
{
}

Public Person(String name)
{
this();
this.name = name;
}
}

【实例 2】:死循环

class Person
{
private String name;

Public Person()
{
this("haha");
}

Public Person(String name)
{
this();
this.name = name;
}
}

六. static关键字

1. static(静态)关键字

【用法】: (1)是一个修饰符,用于修饰成员(成员变量,成员函数) Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

【分析】:static静态修饰的内容,被对象所共享。
     static String country = “cn”;被提取出来,不放在堆内存中,每个对象都可以访问。

(2)当成员被静态修饰后,就多了一个调试方法,除了可以被对象调用外,还可以直接被类名调用
   用法:类名 . 静态成员

   [e.g.] Person p = new Person();
       System.out.println(p.country); //有对象
     =>System.out.println(Person.country); //没有对象

【注意】:要区分什么是共享数据,什么不共享,不建议定义多个static。

     [e.g.] 饮水机共享,杯子每个人特有不共享。特有内容随对象存储。

【特点】: (1)随着类的加载而加载:

   也就是说,静态会随着类的消失而消失,说明它的生长周期最长。
   当类一加载到内存中,已经加载在内存中了。

  【实例】:
   class Person
   {
     private String name;
     //【非静态成员变量,实例变量】:对象存在该变量存在;对象不存在,该变量就不存在。

     static String country = “cn”;
     //【静态成员变量,类变量】:当它存在时,对象还没存在,所以调用时类来调用。
   }

(2)优先于对象存在:

   明确一点:静态是先存在的,对象是后存在的。

(3)被所有对象所共享

(4)可以直接被类名所调用

【实例变量和类变量的区别】: (1)存放位置 实例变量:随着对象的加载而存在于堆内存中
类变量:随着类的加载而存在于方法区中

(2)生命周期 实例变量:随着对象的消失而消失
类变量:随着类的消失而存在消失,生命周期最长

【使用注意事项】: (1)静态方法只能访问静态成员。非静态方法既可以访问静态也可以访问非静态。

  【实例】:
   public static void show()
   {
     //System.out.println(this.name); //[错误]
     //this.speak(); //[错误]
   }
   public void speak()
   {
     System.out.println(this.name); //[正确]
     show(); //[正确]
   }

(2)静态方法中不可以定义this, super关键字。
   因为静态优先存在于对象存在,所以静态方法中不可以出现this, super。
(3)main主函数是静态的。

【静态有利有弊】: 利: 对对象的共享数据进行单独空间的存储,节省空间,
没必要每个对象中存储一份,可以直接被类名调用。
弊: 生命周期过长,访问出现局限性(静态虽好,只能访问静态)

【什么时候使用静态?】: (1)什么时候定义静态变量(类变量):

   当对象中出现共享数据值时,该数据被静态所修饰,
   对象中的特有数据(姓名是共享属性而不是共享数据)要定义在非静态中,存在于堆内存中。

(2)什么时候定义静态函数:

   当功能内部没有访问到非静态数据(对象特有数据),那么该功能可以定义成静态的。


2. 主函数 main

public static void main(String[] args)
主函数是一个特殊的函数,可以被JVM调用,作为程序入口。是固定格式。

【主函数的定义】: public: 代表着该函数访问权限是最大的。(被JVM访问)
static: 代表主函数随着类的加载就已经存在了。
void: 主函数没有具体的返回值。
main: 不是关键字,但是是一个特殊的单词,可以被JVM识别。
函数参数(String[] args): 参数类型是一个数组,该数组中的元素是字符串,也称字符串类型数组


【实例】:测试主函数参数长度。main可以重载,但入口只有一个。

public class Demo {
public static void main(int x) { //可以重载

}

public static void main(String[] args) { //程序的入口,先运行,【args参数名】:可以更改,全称:arguments
System.out.println(args.length); //结果为0

}
}
/*引用类型数据,能接收两种值:null,和具体值
1. String[] args = null;
2. String[] args = new String[2];*/


JVM在调用主函数时,传入的是new String[0],长度为0。

Javac: 启动底层编译器。
Java: Java对外提供的功能,启动底层的JVM,JVM执行Demo这个类,类中的方法被JVM调用。
设置主函数的参数: java Demo haha hehe heihei:将类后面跟的这些数据,自动的存入数组中,即定义长度为3的数组。
【Demo 】:类名
【haha hehe heihei】:主函数的参数,角标从0开始。


【实例】:JVM调用Demo的主函数,Demo调用DemoTest的主函数。实现在程序中设置主函数的参数。

public class Demo {

public static void main(String[] args) {
String[] arr = {"x", "y", "z"};
DemoTest.main(arr);
}
}
public class DemoTest {

public static void main(String[] args) {
for(int i = 0; i < args.length; i++) //打印主函数参数列表
{
System.out.println(args[i]);
}
}
}

3. 静态的应用

每一个应用程序中都有共性的功能,可以将这些功能抽取,独立封装,以便复用。

【实例】:将操作数据的功能抽取,放入ArrayTool类中。

 虽然可以通过建立ArrayTool对象使用这些工具方法,对数组进行操作。

 [发现了问题]:

  1. 对象是用于封装数据的,可是ArrayTool对象并没有封装特有数据。

  2. 操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。
    => 所以这时就考虑,让程序更严谨,是不需要对象的。
      可以将ArrayTool中的方法都定义成static的,直接通过类名调用。

  3. 将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的。
    => 所以为了更加谨慎,强制让该类不能建立对象,避免堆内存中出现乱七八糟对象。
      可以将构造函数私有化完成。
public class Demo {

public static void main(String[] args) {
int[] arr = {5,1,6,4,2,8,9};
System.out.println("-------------排序前-------------");
ArrayTool.printArray(arr);
ArrayTool.selectSort(arr); //选择排序
System.out.println("-------------排序后-------------");
ArrayTool.printArray(arr);

}
}

/**
这是一个可以对数组进行操作的工具类,有获取最值,排序等功能。
@author
佳露
@version
V1.1
*/

public class ArrayTool
{

/**
* 私有化空参数构造函数,不能建立实体对象,无法实例化
*/

private ArrayTool(){}

/**
* 获得数组最大值max
* @param arr 数组
* @return 最大值
*/

public static int getMax(int[] arr)
{
int max = arr[0];
for (int i=1; i<arr.length; i++)
{
if(max < arr[i])
max = arr[i];

}

return max;
}

/**
* 获得数组最小值min
* @param arr 数组
* @return 最小值
*/

public static int getMin(int[] arr)
{
int min = arr[0];
for (int i=1; i<arr.length; i++)
{
if(min > arr[i])
min = arr[i];

}

return min;
}

/**
* 直接插入排序 + 希尔排序 + space取整
* @param arr 数组
*/

public static void shellSort(int[] arr)
{
int space = arr.length;
do
{
space >>= 1; // space = space/2;

for (int i = space; i < arr.length; i++) { //在直接排序的基础上,将间隔1,改为space
if(arr[i] < arr[i-space])
{
int temp = arr[i], j;
for (j = i - space; j >= 0 && arr[j] > temp; j -= space) {
arr[j + space] = arr[j];
}
arr[j + space] = temp;
}
}

}while(space > 0);
}

/**
* 直接插入排序 + 希尔排序 + space四舍五入
* @param arr 数组
*/

public static void shellSort2(int[] arr)
{
double spaceD = arr.length;
int space;
do
{
spaceD = Math.ceil(spaceD / 2); //四舍五入
space = (int)spaceD;

for (int i = space; i < arr.length; i++) { //在直接排序的基础上,将间隔1,改为space
System.out.println("arr[i-space="+arr[i-space]);
System.out.println("arr[i]="+arr[i]);
if(arr[i] < arr[i-space])
{
int temp = arr[i], j;
for (j = i - space; j >= 0 && arr[j] > temp; j -= space) {
System.out.println("arr[j]="+arr[j]);
arr[j + space] = arr[j];
}
arr[j + space] = temp;
printArray(arr);
}
}

}while(space != 1); //由于四舍五入,最后space一定为1
}

/**
* 直接插入排序
* @param arr 数组
*/

public static void insterSort(int[] arr)
{
for (int i = 1; i < arr.length; i++) {
if(arr[i] < arr[i-1])
{
int temp = arr[i], j;
for (j = i - 1; j >= 0 && arr[j] > temp; j--) {
arr[j + 1] = arr[j];
}
arr[j + 1] = temp;
}
}
}

/**
* 冒泡排序
* @param arr 数组
*/

public static void bubbleSort(int[] arr)
{
for (int i = 0; i < arr.length - 1; i++) {

int j = 0, max = 0; //max 记录最大值的角标

for (j = 1; j < arr.length - i; j++) {
if(arr[j] > arr[max])
{
max = j;
}
}
if(j-1 != max) //如果max 角标不等于最后一个角标,两数交换
{
swap(arr, j-1, max); //两数交换
}
}
}


/**
* 选择排序
* @param arr 数组
*/

public static void selectSort(int[] arr)
{
for (int i = 0; i < arr.length - 1; i++) {
for(int j = i + 1; j < arr.length; j++)
{
if(arr[i] > arr[j])
{
swap(arr, i, j); //两数交换
}
}
}
}

/**
* 交换数组中的两个元素
* @param arr 数组
* @param i 数组角标i
* @param j 数组角标j
*/

private static void swap(int[] arr, int i, int j)
{
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];
}

/**
* 打印数组
* @param arr 数组
*/

public static void printArray(int[] arr)
{
for (int i = 0; i < arr.length; i++) {
if( i != arr.length -1)
{
System.out.print(arr[i] + ", ");
}
else
{
System.out.println(arr[i]);
}
}
}
}

5. 帮助文档的制作

帮助文档:API文档(应用程序接口)
开始制作程序的说明书,Java的说明书通过文档注释来完成。

【文档注释】: [ @author ]:作者
[ @version ]:版本号
[ @param ]:参数
[ @return ]:返回值

【帮助文档的制作】: javadoc -d myhelp -author -version ArrayTool.java

[ -d ]:当前文件夹下
[ myhelp ]:文件夹名

【类修饰符】: private:私有的不被做成说明文档。
public 和 protect(保护)才被做成说明文档。

【默认构造函数的权限】: 一个类中默认会有一个空参数的构造函数,这个默认的构造函数的权限和所属类一致。
如果类被public修饰,那么默认的构造函数也带public修饰,如果没有,则也没有。
=>默认构造函数的权限是随类的变化而变化。


6. 静态代码块

【格式】: static
{
  静态代码块中的执行语句;
}

【特点】: 随着类的加载而执行,只执行一次。用于给类进行初始化的。
一个类进内存,不需要对象的情况下,做一些事,优先于主函数,优先于对象。


【实例 1】:static代码块执行过程

public class Demo { // [1]类加载进内存

static // [2]类初始化
{
System.out.println("b");
}

public static void main(String[] args) {
new StaticCode(); // [4]类初始化
new StaticCode(); // [4]类初始化,已经定义了,第二次不再执行。
System.out.println("over"); // [5]输出执行
}

static // [3]类初始化:优先于主函数
{
System.out.println("c");
}

}
class StaticCode
{
static // [4]类初始化
{
System.out.println("a");
}
}

/*[输出结果]:b c a over*/

【实例 2】:static代码块可以验证类有无加载

public class Demo {

public static void main(String[] args) {
//[1]
//StaticCode.show(); // 加载了类,[输出结果]: a show run

//[2]
//StaticCode sc = new StaticCode();// 加载了类,用的了构造方法。 [输出结果]: a

//[3]
//StaticCode sc = null;// 没有加载类,sc没有指向。 [输出结果]: (没有输出)

/*用到类中的内容,才加载类。*/
}

}
class StaticCode
{
static
{
System.out.println("a");
}

public static void show()
{
System.out.println("show run");
}
}

【实例 3】:构造函数(有无参数),构造代码块,静态代码块执行过程

public class Demo {

public static void main(String[] args) {
StaticCode sc = new StaticCode(4); // 类加载,调用有参构造函数。
}

}
class StaticCode
{
int num = 9;

/**
* 无参构造函数,初始化对应对象
*/

public StaticCode()
{
System.out.println("b");
}

/**
* 带参数构造函数,初始化对应对象 [3] 对应对象初始化
*/

public StaticCode(int x)
{
System.out.println("d");
}

/**
* 静态代码块,初始化类 [1] 类初始化
*/

static
{
System.out.println("a");
}

/**
* 构造代码块,初始化对象 [2] 所有对象初始化
*/

{
System.out.println("c" + this.num);
}
}

/*[输出结果]:a c9 d*/

7. 对象建立,对象调用非静态方法内存分配

【实例】:分析以下代码的内存分配情况

public class Demo {

public static void main(String[] args) {
Person p = new Person("zhangshan", 20);
}

}
class Person
{
private String name = "haha";
private int age;
private static String country = "CN";

public Person(String name, int age)
{
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public void speak()
{
System.out.println("name=" + name + ", age=" + age);
}

public static void showCountry()
{
System.out.println("country=" + country);
}
}


Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

【对象建立过程步骤】:

  1. 因为new用到了Person.class,所以会先找到Person.class文件,并加载到内存中。通过JVM。
  2. 执行该类的static代码块,如果有的话,给Person.class类进行初始化。
  3. 在堆内存中开辟空间,分配内存地址。
  4. 在堆内存中建立对象的特有属性,并进行默认初始化。
  5. 对属性进行显示初始化。
  6. 对对象进行构造代码快初始化。
  7. 对对象进行对应的构造函数初始化。
  8. 将内存地址赋值给栈内存中的p变量。


Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

七. 单例设计模式:

设计模式:让问题简单化,解决某一类问题最行之有效的方法。Java有23种设计模式。
单例设计模式:解决一个类在内存只存在一个对象,类似配置文件。

【想要保住对象唯一】:

  1. 为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象。
  2. 还为了其他程序可以访问到该类对象,只好在本类中,自定义一个对象。
  3. 为了方便其他程序对自定义对象的访问,可以对我提供一些访问方式。

【这三步怎么用代码体现呢?】

  1. 将构造函数私有化。
  2. 在类中创建一个本类对象。
  3. 提供一个方法可以获取到该对象。

【注】:对于事物该怎么描述,还是怎么描述。当需要将事物的对象保证在内存中唯一时,就就将以上三步加上即可。

【实例 1】:饿汉式

public class Demo {

public static void main(String[] args) {
Single s1 = Single.getInstance();
Single s2 = Single.getInstance();
}

}
/**
* 【饿汉式】
*/

class Single
{
private Single(){}
private static Single single = new Single();
public static Single getInstance()
{
return single;
}
}


Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

【饿汉式特点】:Single类一进内存就已经创建好了对象,这是初始化对象,成为饿汉式。

【实例 2】:懒汉式

public class Demo {

public static void main(String[] args) {
Single s1 = Single.getInstance();
Single s2 = Single.getInstance();
}

}
/**
* 【懒汉式】
*/

class Single
{
private Single(){}
private static Single single = null;
public static synchronized Single getInstance()
{
if(single == null)
{
single = new Single();
}
return single;
}
}


Java基础---面向对象(面向对象,类,对象,匿名对象,封装,构造函数,构造代码块,this,static,main,帮助文档,静态代码块,单例)

【懒汉式】:对象是方法被调用时,才初始化,也叫做对象的延时加载,称为懒汉式。

【懒汉式的特点】:Single类进内存,对象还没有存在,只有调用getInstance方法时,才建立对象。

【实例】:懒汉式多线程调用

/**
* 【懒汉式】
*/

class Single
{
private Single(){}
private static Single single = null;
//法一:(低效的)
// public static synchronized Single getInstance()
// {
// if(single == null)
// {
// single = new Single();
// }
// return single;
// }

//法二:(高效的)
public static Single getInstance()
{
if(single == null)
{
synchronized(Single.class)
{
if(single == null)
{
single = new Single();
}
}
}
return single;
}
}

【记住原则】:定义单例,建议使用饿汉式。