三.面向对象(一)
转载自:Java笔记目录
1.面向对象(一)
面向过程与面向对象的区别(蛋炒饭VS盖饭)
为什么会出现面向对象分析方法?
因为现实世界太复杂多变,面向过程的分析方法无法满足。
面向过程
采用面向过程必须了解整个过程,每个步骤都有因果关系,每个因果关系都构成了一个步骤,多个步骤就构成了一个系统,因为存在因果关系每个步骤很难分离,非常紧密,当任何一步骤出现问题,将会影响到所有的系统。如:采用面向过程生产电脑,那么他不会分CPU、主板和硬盘,它会按照电脑的工作流程一次成型。代码间耦合度(代码间的关联)强,牵动任何一个因果关系会影响整个系统的运行。
面向对象
面向对象对会将现实世界分割成不同的单元(对象),实现各个对象,如果完成某个功能,只需要将各个对象协作起来就可以。
【1】(了解)面向对象 vs 面向过程
例子:人开门;把大象装冰箱
理解一:人开门
//面向过程:人 打开 门 //面向对象: 人{ 打开(门){ 门.开开(); } }
门{ 开开(){ } }
理解二:人把大象装进冰箱
//面向过程:1)打开冰箱2)把大象放进去 3)关闭冰箱门 //面向对象: 人{ 打开(冰箱){冰箱.开开();} 操作(大象){大象.进入(冰箱)} 关闭(冰箱){冰箱.合上()} } 大象{ 进入(冰箱){} } 冰箱{ 开开(){} 合上(){} }
【2】面向对象的编程关注于类的设计!
1)一个项目或工程,不管多庞大,一定是有一个一个类构成的。
2)类是抽象的,好比是制造汽车的图纸。
而具体的一辆一辆的车,是根据图纸制造的,实际上就是类的实例化
【3】完成一个项目(或功能)的思路
1)所要完成的功能对应的类的对象是否存在。
2)若存在,则通过对象直接调用对应的类中的属性或方法即可
3)若不存在,需要创建类的对象。甚至说,类都不存在,就需要设计类。
【4】面向对象编程的三条主线:
1)类及类的构成成分:属性 方法 构造器 代码块 内部类
2)面向对象编程的三大特征:封装性 继承性 多态性 (抽象性)
3)其它的关键字:this super package import static final abstract interface ...
【5】从软件的开发的生命周期来看,基于面向对象可以分为三个阶段:
1)OOA(面向对象的分析)
2)OOD(面向对象的设计)
3)OOP(面向对象的编程)-----Java 就是一个纯面向对象的语言
1.1类
1.1.1 类的概念
l 类(class)和对象(object)是面向对象的核心概念。
- 类是对一类事物描述,是抽象的、概念上的定义;对现实世界中具有共性的事物进行抽象就形成了类;类是一种引用类型;类在现实世界中是不存在的,是人们大脑抽象出来的一个概念。
- 对象是实际存在的该类事物的每个个体,因而也称实例(instance)。
- “万事万物皆对象”

1.1.2 类及类的成员
现实世界万事万物是由分子、原子构成的。同理,Java代码世界是由诸多个不同功能的类构成的。现实世界中的分子、原子又是由什么构成的呢?原子核、电子!那么,Java中用类class来描述事物也是如此,类的成员有:属性(Field)、方法(Method)、构造器、代码块以及内部类。
class Person{ //属性或成员变量 String name; boolean isMarried; //构造器 public Person(){} public Person(String n,boolean im){ name = n;isMarried = im; } //方法或函数 public void walk(){ System.out.println("人走路..."); } public String display(){ return "名字是:" + name + ",Married:" + isMarried; } //代码块 { name = "HanMeiMei"; age = 17; isMarried = false; } //内部类 class pet{ String name; float weight; } }
1.1.3 类的定义
类型修饰符 class 类名 extends 父对象名称 implements 接口名称{ 属性声明; 方法声明; }
说明:修饰符public:类可以被任意访问。类的正文要用{ }括起来
public class Person{ //声明私有变量 age private int age ; //声明方法showAge() public void showAge(int i) { age = i; } }
【创建Java自定义类的步骤】
①定义类(考虑修饰符、类名)
②编写类的属性(考虑修饰符、属性类型、属性名、初始化值)
③编写类的方法(考虑修饰符、返回值类型、方法名、形参等)
1.1.4 类的成员之一:属性
语法格式:
修饰符 类型 属性名 = 初值 ;
说明: 修饰符private: 该属性只能由该类的方法访问。修饰符public: 该属性可以被该类以外的方法访问。类型:任何基本类型,如int、boolean或任何类。
public class Person{ //声明private变量 age private int age; //声明public变量 name public String name = “Lila”; }
成员变量(属性)和局部变量的区别:
l 成员变量:在方法体外,类体内声明的变量
- 成员变量定义在类中,在整个类中都可以被访问。
- 成员变量分为类成员变量(以static修饰)和实例成员变量(不以static修饰),实例变量存在于对象所在的堆内存中。
- 成员变量有默认初始化值,为该类型的默认值。
- 成员变量的权限修饰符可以根据需要,选择任意一个
l 局部变量:在方法体内部声明的变量
- 局部变量只定义在局部范围内,如:形参(方法签名中定义的变量)、方法内、代码块内等。
- 局部变量存在于栈内存中。
- 作用的范围结束,变量空间会自动释放。
- 局部变量没有默认初始化值,每次必须显式初始化(形参不用)。
- 局部变量声明时不指定权限修饰符
1.1.5 类的成员之二:方法
语法格式:
修饰符 返回值类型 方法名 (参数列表) {
方法体语句;
}
说明:修饰符:public, private等。返回值类型:return语句传递返回值。没有返回值:void。
public class Person{ private int age; //声明方法getAge public int getAge() { return age; } //声明方法setAge public void setAge(int i) { //将参数i的值赋给类的成员变量age age = i; } }
1.1.6 类的成员之三:构造方法(构造器、构造函数,Constructor)
构造方法主要用来创建类的实例化对象,可以完成创建实例化对象的初始化工作。
语法:
[修饰符列表] 构造方法名(形式参数列表){
方法体;
}
说明:构造方法的方法名必须和类名一致;构造方法修饰符列表:public、proteced、private
构造方法的作用:
①创建对象
②给创建的对象的属性(成员变量)赋值,即初始化成员变量。
构造方法应该如何调用?
new 构造方法名(实参); //在堆中开辟空间存储对象
注意:
①如果一个类没有提供任何构造方法,系统默认提供无参数构造方法。如果一个类已经手动的提供了构造方法,那么系统不会再提供任何构造方法。
②成员变量到底什么时候赋值:只有在调用构造方法的时候,才会给成员变量赋值。
③类的多个构造器之间构成重载
④类对象的属性赋值的先后顺序:属性的默认初始化>属性的显式初始化>通过构造器给属性初始化>通过"对象.方法"的方式给属性赋值
【eclipse操作】
快速生成构造器:菜单栏Source à Generate Constrctor using Fields…
快速生成get,set方法:菜单栏Source à Generate Getters and Setters…
1.1.7 类的访问机制
在一个类中,类中的方法可以直接访问类中的成员变量(例外:static方法访问非static,编译不通过)。在不同类中,先创建要访问类的对象,再用对象访问类中定义的成员。
1.1.8 类的内存

Animal a3=a1;a3.name=“维尼熊”; //此时若将a3的属性改变,那a1的属性也被改变了
//a3不意味着相较于a1重新创建的一个对象,而是a1与a3共用一个对象实体
1.2对象
1.2.1 对象的创建和使用
①使用new + 构造器创建一个新的对象;
②使用“对象名.对象成员”的方式访问对象成员(包括属性和方法)。
public class Animal { public int legs; public void eat(){ System.out.println(“Eating.”); } public viod move(){ System.out.println(“Move.”); } }
public class Zoo{ public static void main(String args[]){ Animal xb=new Animal(); xb.legs=4; System.out.println(xb.legs); xb.eat(); xb.move(); } }
1.2.2 对象的产生
当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值。除了基本数据类型之外的变量类型都是引用类型,如下面的Person及前面讲过的数组。
class Person{ int age; void shout(){ System.out.println(“oh,my god! I am ” + age); } }
Person p1 = new Person();//执行完后的内存状态

1.2.3 对象的使用
class TestPerson{ public static void main(String[] args) {
//程序运行的内存布局如下图 Person p1 = new Person(); Person p2 =new Person(); p1.age = -30; p1.shout(); p2.shout(); }
}

1.2.4 对象的生命周期

1.2.5 对象的内存结构
练习:根据代码,画出内存图
class Car{ String color = "red"; int num = 4; void show(){ System.out.println("color="+color+"..num="+num); } } class TestCar { public static void main(String[] args) { Car c1 = new Car(); //建立对象c1 Car c2 = new Car(); //建立对象c2 c1.color = "blue"; //对对象的属性进行修改 c1.show(); //使用对象的方法 c2.show(); } }

1.2.6 匿名对象
①我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象。
如:new Person().shout();
②使用情况
如果对一个对象只需要进行一次方法调用,那么就可以使用匿名对象。我们经常将匿名对象作为实参传递给一个方法调用。
1.3再谈方法
1.3.1 什么是方法(函数)
①方法是类或对象行为特征的抽象,也称为函数。
②Java里的方法不能独立存在,所有的方法必须定义在类里。
|
修饰符 返回值类型 方法名(参数类型 形参1,参数类型 形参2,….){ 程序代码 return 返回值; } |
形式参数:在方法被调用时用于接收外部传入的数据的变量。
参数类型:就是该形式参数的数据类型。
返回值:方法在执行完毕后返还给调用它的程序的数据。
返回值类型:方法要返回的结果的数据类型。
实参:调用方法时实际传给函数形式参数的数据。
思考:如何理解方法返回值类型为void的情况 ?
1.3.2 方法的调用
方法只有被调用才会被执行;
方法调用的过程分析:

注 意:
①没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的return语句如果在最后一行可以省略不写。
②定义方法时,方法的结果应该返回给调用者,交由调用者处理。
③方法中只能调用方法,不可以在方法内部定义方法。
输入语句:
|
import java.util.Scanner;//不是自己创建的,要导入包 //实例化Scanner类的对象,通过此对象.nextXxx()调用,完成相应的功能。 Scanner s = new Scanner(System.in); int i = s.nextInt(); |
1.3.3 方法的重载(overload)
要求:
①同一个类中
②方法名必须相同
③方法的参数列表不同(个数、类型或顺序不同)
注意:方法的重载与方法的返回值类型没有关系!
【eclipse快捷键】
1.单行注释:Ctrl +/,再次取消。
2.多行注释:Ctrl+shift +/,Ctrl+shift +\(反斜杠)取消。
3.格式化:Ctrl+shift+F
1.3.4 可变个数的形参的方法
格式:
对于方法的形参: 数据类型 ... 形参名
①可变个数的形参的方法与同名的方法之间构成重载
②可变个数的形参在调用时,个数从0开始,到无穷多个都可以。
③使用可变多个形参的方法与方法的形参使用数组是一致的。
④若方法中存在可变个数的形参,那么一定要声明在方法形参的最后。
⑤在一个方法中,最多声明一个可变个数的形参。
|
//如下四个方法构成重载 //在类中一旦定义了重载的可变个数的形参的方法以后,如下的两个方法可以省略 // public void sayHello(){ // System.out.println("hello world!"); // } // public void sayHello(String str1){ // System.out.println("hello " + str1); // } //可变个数的形参的方法 public void sayHello(String ... args){ for(int i = 0;i < args.length;i++){ System.out.println(args[i] + "$"); } //System.out.println("====="); }
public void sayHello(int i,String ... args){ //public void sayHello(String ... args,int i){ System.out.println(i);
for(int j = 0;j < args.length;j++){ System.out.println(args[j] + "$"); } }
public void sayHello1(String[] args){ for(int i = 0;i < args.length;i++){ System.out.println(args[i]); } } //可变个数形参的使用的例子 // public int getSum(int i,int j){ // return i + j; // } // public int getSum(int i,int j,int k){ // return i + j + k; // } public int getSum(int ... args){ int sum = 0; for(int i = 0;i < args.length;i++){ sum += args[i]; } return sum; } |
1.3.5 Java内存的主要划分
好书推荐:深入java虚拟机第二版(重点第五章)


|
//对象没有更多的引用指向,则变成垃圾. public class OOTest03{ public static void main(String[] args){ //u1是引用,保存内存地址指向堆中的对象。 User u1 = new User(); //程序执行到此处,u1不再指向堆中的对象。 //对象变成了垃圾。 u1 = null; //使用一个空的引用去访问成员,会出现什么问题? //System.out.println(u1.name); //java.lang.NullPointerException (空指针异常)
Star s = new Star(); s = null; s.sing(); //java.lang.NullPointerException } } class Star{ //成员方法 public void sing(){ System.out.println("Sing a song!"); } } |
1.3.6 Java的值传递机制
方法的值的传递:
①形参:方法声明时,方法小括号内的参数
②实参:调用方法时,实际传入的参数的值
规则:java中的参数传递机制:值传递机制
①形参是基本数据类型的:将实参的值传递给形参的基本数据类型的变量
②形参是引用数据类型的:将实参的引用类型变量的值(对应的堆空间的对象实体的首地址值)传递给形参的引用类型变量。
以下程序传递基本数据类型:
|
public class OOTest04{ public static void m1(int i){ i++; System.out.println("m1--->" + i); //11 } public static void main(String[] args){ //入口 int i = 10; //局部变量 m1(i); //调用 System.out.println("main--->" + i); //10 } } |

以下程序传递引用数据类型:
|
public class OOTest05{ public static void m1(Animal a){ a.age++; System.out.println("m1--->" + a.age); //11 } //入口 public static void main(String[] args){ //1.创建Animal对象 Animal a = new Animal(10);
m1(a);
System.out.println("main--->" + a.age); //11 } } //动物 class Animal{
//Field int age;
//Constructor Animal(int _age){ age = _age; } } |

【例题1】
|
public static void main(String[] args) { TestArgsTransfer tt = new TestArgsTransfer(); int i = 10; int j = 5; System.out.println("i:" + i + " j:" + j);//i : 10 j : 5 // //交换变量i与j的值 // int temp = i; // i = j; // j = temp; tt.swap(i, j);//将i的值传递给m,j的值传递给n System.out.println("i:" + i + " j:" + j);//i : 10 j : 5 } //定义一个方法,交换两个变量的值 public void swap(int m,int n){ int temp = m; m = n; n = temp; System.out.println("m:" + m + " n:" + n); } |
使用swap方法前后内存结构:


【例题2】
|
public class TestArgsTransfer1 { public static void main(String[] args) { TestArgsTransfer1 tt = new TestArgsTransfer1(); DataSwap ds = new DataSwap(); System.out.println("ds.i:" + ds.i + " ds.j:" + ds.j); tt.swap(ds); System.out.println(ds); System.out.println("ds.i:" + ds.i + " ds.j:" + ds.j); } //交换元素的值 public void swap(DataSwap d){ int temp = d.i; d.i = d.j; d.j = temp; System.out.println(d);//打印引用变量d的值 } } class DataSwap{ int i = 10; int j = 5; } |

【例题3】
|
class Value { int i = 15; } class Test { public static void main(String argv[]) { Test t = new Test(); t.first(); } public void first() { int i = 5; Value v = new Value(); v.i = 25; second(v, i); System.out.println(v.i); } public void second(Value v, int i) { i = 0; v.i = 20; Value val = new Value(); v = val; System.out.println(v.i + " " + i); } } |

1.4 面向对象的特征一:封装性
当创建了类的对象以后,如果直接通过"对象.属性"的方式对相应的对象属性赋值的话,可能会出现不满足实际情况的意外,我们考虑不让对象来直接作用属性,而是通过"对象.方法"的形式,来控制对象对属性的访问。实际情况中,对属性的要求就可以通过方法来体现。
封装性的思想:
①将类的属性私有化②提供公共的方法(setter & getter)来实现调用
四种权限修饰符:置于类的成员定义前,用来限定对象对该类成员的访问权限
①权限从大到小为:public > protected > 缺省 > private
②四种权限都可以用来修饰属性、方法、构造器
③对于类(class)的权限修饰只可以用:public和default(缺省)
public类可以再任意地方被访问
default类只可以被同一个包内部的类访问

【举例】
|
public class Animal{ //private 修饰的属性,只能在本类中被调用,出了此类,就不能被调用了。 private String name;//动物的名字 private int legs;//腿的个数 String color; public double weight; void eat(){ System.out.println("动物进食"); } public void sleep(){ System.out.println("动物睡觉"); } public void info(){ System.out.println("name:" + name + " legs:" + legs); } //设置类的属性 public void setLegs(int l){ if(l > 0 && l % 2 == 0){ legs = l; }else{ System.out.println("您输入的数据有误!"); } } //获取类的属性 public int getLegs(){ return legs; } // public int doLegs(int l){ // legs = l; // return legs; // }//方法要单纯一点,只有一个功能 public void setName(String n){ //.... name = n; } public String getName(){ return name; } } |
1.5 this关键字
1.5.1 this是什么?
this是一个引用类型,堆中的每一个java对象上都有this, this保存内存地址指向自身。
1.5.2 this能用在哪些地方?
①this可以用在成员方法中。
②this可以用来区分成员变量和局部变量:
当局部变量(形参)和成员变量重名的时候,如果在方法内部需要使用成员变量,必须
添加this来表明该变量时类成员。
③this可以用在构造方法中。
在构造方法中使用“this(形参列表)”显式的调用本类中重载的其它的构造器(用一个构造方法调用另一个构造方法)。
语法:this(实参);
目的:代码重用。
要求:“this(形参列表)”要声明在构造器的首行!
注意:若一个类中有n个构造器,那么最多有n-1个构造器中使用了this(形参)。
1.5.3理解“this”
|
public class ThisTest01{ public static void main(String[] args){ /* //创建对象 MyDate t1 = new MyDate(2008,8,8); System.out.println(t1.year+"年"+t1.month+"月"+t1.day+"日"); //创建对象 MyDate t2 = new MyDate(2012,12,20); System.out.println(t2.year+"年"+t2.month+"月"+t2.day+"日"); */ MyDate t3 = new MyDate(); System.out.println(t3.year+"年"+t3.month+"月"+t3.day+"日"); } } //日期 class MyDate{ //Field int year; int month; int day; //Constructor //需求:在创建日期对象的时候,默认的日期是:1970-1-1 MyDate(){ this(1970,1,1);//this用在构造方法中 /* this.year = 1970; this.month = 1; this.day = 1; */ } MyDate(int _year,int _month,int _day){ year = _year; month = _month; day = _day; } } |

1.5.4 this用在成员方法中
|
public class ThisTest02{ public static void main(String[] args){ //创建对象 Employee e = new Employee(7369,"SMITH"); //工作 e.work(); //创建对象 Employee e1 = new Employee(7370,"FORD"); //工作 e1.work(); e.m1(); } } class Employee{ //员工编号 int empno; //员工名 String ename; //Constructor Employee(){} Employee(int _empno,String _ename){ empno = _empno; ename = _ename; } //提供一个员工工作的方法. //this用在成员方法中,谁去调用这个成员方法,this就代表谁。 //this指的就是当前对象。 public void work(){ System.out.println(this.ename + "在工作"); //System.out.println(ename + "在工作"); //this. 可以省略 } //成员方法 public void m1(){ this.m2(); m2(); } //成员方法 public void m2(){ System.out.println("TESTING"); }
} |
1.5.5 this用来区分成员变量和局部变量。
|
public class ThisTest03{
public static void main(String[] args){
Manager m1 = new Manager("KING");
Manager m2 = new Manager(); m2.setName("FORD");
System.out.println(m1.getName()); //KING System.out.println(m2.getName()); //FORD }
}
class Manager{
//Field private String name;
//Constructor Manager(){}
Manager(String name){ this.name = name; }
//Method //成员方法 public void setName(String name){ this.name = name; }
//成员方法 public String getName(){ //return name; return this.name; }
} |
1.5.6 this不能用在静态方法中:
静态方法的执行根本不需要java对象的存在。直接使用 类名. 的方式访问。而this代表的是当前对象。所以静态方法中根本没有this。
|
public class ThisTest04{ String str; //入口 public static void main(String[] args){ Person.m1(); //str是一个成员变量,必须由“引用. ”访问 //System.out.println(str);
ThisTest04 tt = new ThisTest04(); System.out.println(tt.str); //null } } class Person{ //Field String name; //Constructor Person(){} Person(String name){ this.name = name; } //静态方法 public static void m1(){ //System.out.println(this.name); //如果要想访问name只能: Person p1 = new Person("刘德华"); System.out.println(p1.name); } } |
1.6 static关键字
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。

1.6.1 什么是static
静态的,可以用来修饰属性、方法、*代码块(或初始化块)、*内部类
1.6.2 static修饰属性(类变量)
static修饰的变量叫做静态变量。
①由类创建的所有的对象,都共用这一个属性
②当其中一个对象对此属性进行修改,会导致其他对象对此属性的一个调用。vs 实例变量(非static修饰的属性,各个对象各自拥有一套副本)
③类变量随着类的加载而加载的,而且独一份
④静态的变量可以直接通过“类.类变量”的形式来调用
⑤类变量的加载是要早于对象。所以当有对象以后,可以“对象.类变量”使用。但是"类.实例变量"是不行的。
⑥类变量存在于静态域中。
|
public class StaticTest04{ public static void main(String[] args){ Animal a1 = new Animal("AAA",10); Animal a2 = new Animal("BBB",11); //如何访问(类名.) System.out.println(Animal.type); //也可以使用 引用. System.out.println(a1.type); Animal a3 = null; System.out.println(a3.type); //静态变量底层访问的时候一定使用的 类名. 和对象无关,不会出现空指针异常。 } } //抽象现实世界中的“陆生”动物 class Animal{ //Field //成员变量(一个对象一份.) //成员变量在创建对象的时候初始化,并且存储在堆中的每一个对象中。 String name; int age; //静态变量,被存储在方法区. //所有的java对象共享这一份。 //所以静态变量是类级别的,使用“类名.”的方式访问. static String type = "陆生"; //Constructor Animal(String name,int age){ this.name = name; this.age = age; } } |


【补充】
变量分类:①局部变量②成员变量(实例变量,非静态变量) ③静态变量(方法区)
成员变量:创建java对象的时候初始化。
静态变量:在类加载阶段赋值,并且只赋值一次。
什么时候变量声明成静态变量?
如果这个属性所有的对象都有,并且这个属性的值是相同的,则该属性声明成静态的属性。
1.6.3 static修饰方法(类方法)
static修饰的方法叫做静态方法。
①随着类的加载而加载,在内存中也是独一份
②可以直接通过“类.类方法”的方式调用
③内部可以调用静态的属性或静态的方法,而不能调用非静态的属性或方法。反之,非静态的方法是可以调用静态的属性或静态的方法
④静态的方法内是不可以有this或super关键字的!
注意:静态的结构(static的属性、方法、代码块、内部类)的生命周期要早于非静态的结构,同时被回收也要晚于非静态的结构。一般情况下工具类中的方法大部分都是静态方法。静态方法不用创建对象也能直接访问该方法。
|
public class StaticTest03{ //成员方法 //成员方法必须使用“引用.”调用 public void m1(){ } //静态方法 //可以使用“类名.”方式调用.也可以用“引用.”,即使用的是“引用.”,底层还是用的“类名.” //静态方法中不能直接访问非静态数据. //静态方法中不能使用this public static void m2(){ System.out.println("m2...."); } //入口 public static void main(String[] args){ StaticTest03 st = new StaticTest03(); st.m1(); m2(); //静态的方法按照正规的方式访问:“类名.” //静态的方法也能用“引用.”访问 st.m2(); //编译阶段检查出st是StaticTest03类型,编译通过,运行的时候,仍然使用 "StaticTest03."的方式访问。//该方法执行不需要对象。
//空的引用去访问成员的时候会出现空指针异常。 //m2方法不是“成员”而是静态的。 //所以即使引用是空的,也不会报空指针异常。 StaticTest03 s = null; s.m2(); } } |
1.6.4 static定义静态语句块
|
public class StaticTest01{ //静态语句块 static{ System.out.println("1"); } static{ System.out.println("2"); } static{ System.out.println("3"); } static{ System.out.println("4"); } //入口 public static void main(String[] args){ System.out.println("main execute! 1"); System.out.println("main execute! 2"); } } |
1.6.5 static定义实例语句块
每一次调用构造方法之前会执行一次。实例语句块执行顺序也是自上而下。
|
public class StaticTest02{ //静态语句块 static{ System.out.println("A"); } //实例语句块 { System.out.println("1"); } { System.out.println("2"); } { System.out.println("3"); } //构造方法 StaticTest02(){ System.out.println("StaticTest02无参数的构造执行!"); } //入口 public static void main(String[] args){ //调用构造方法 new StaticTest02(); new StaticTest02(); new StaticTest02(); } } |
1.6.6 关于代码的顺序
|
public class StaticTest05{ //编译通过 static int i = 100; static{ System.out.println(i); } //非法向前引用 /* static{ System.out.println(i); } static int i = 100; */} 类{ //可以通过“类名.”,也可以通过“引用.”,即使使用“引用.”底层也是“类名.” //1.静态变量 //2.静态方法 //必须对象存在才可以访问,采用“引用.” //3.成员变量 //4.成员方法 //创建对象,给成员变量赋值 //5.构造方法 //类加载时只执行一次。 //6.静态语句块 //构造方法没调用之前执行一次。 //7.实例语句块 //用在成员方法和构造方法中。 //8.this } 空指针异常:空引用访问成员 |

补充:
1.JavaBean
JavaBean是一种Java语言写成的可重用组件。
所谓javaBean,是指符合如下标准的Java类:
①类是公共的
②有一个无参的公共的构造器
③有属性,且有对应的get、set方法
④用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
举例:
|
public class TestJavaBean{ private String name; //属性一般定义为private private int age; public TestJavaBean(){} public int getAge(){ return age; } public void setAge(int age){ this.age = age; } public String getName(){ return name; } public void setName(String name){ this.name = name; } |
2.UML类图
1.7 单例模式初步
好书推荐:java与模式
1.7.1 什么是设计模式
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索。设计模式是可以重复利用的解决方案,设计模式的提出是在1995 人,是由4 为作者提出的,称为GoF,也就是“四人组”。共23种设计模式。
1.7.2 单例(Singleton)设计模式
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造方法的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
①设计模式从结构上分为三类:创建型、结构性、行为型。
其中最简单的设计模式就是单例了,单例这种模式,尽量少用,也有将其称为“反模式”,缺点是单例模式的类型无法被继承。
②单例模式有什么好处
我们知道对象实例创建完成后,会放到堆中,如果堆中的实例过多,将会存在特别多的
垃圾,这样会导致一些问题,如内存溢出等,使用单例模式后,只会创建一个实例,显著减
少对象实例的个数,同时也会提高性能,因为不会频繁的创建对象,这只是他的一个好处,
其他方面项目中再说。总之,为了保证JVM中某一个类型的java对象永远只有一个,为了节省内存的开销。
③单例模式的三要素
>在类体中需要具有静态的私有的本类型的变量
>构造方法必须是私有的
>提供一个公共的静态的入口点方法
④实现单例模式的两种方式
饿汉式单例:在类加载阶段就创建了对象。
懒汉式单例:用到对象的时候才会创建对象。
|
public class Singleton{ //懒汉式单例 //静态变量 private static Singleton s;
//将构造方法私有化 private Singleton(){}
//对外提供一个公开获取Singleton对象的方法. public static Singleton getInstance(){
if(s==null){ //可能存在线程安全问题的! s = new Singleton(); } return s; } } |
|
public class Customer{ //饿汉式单例模式 //类加载时只执行一次。 private static Customer c = new Customer(); //构造方法私有化 private Customer(){} //提供公开的方法 public static Customer getInstance(){ return c; } } |
|
public class Test01{//测试 public static void main(String[] arg){ /* Singleton s1 = new Singleton(); Singleton s2 = new Singleton(); System.out.println(s1==s2); */ Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); Singleton s3 = Singleton.getInstance();
System.out.println(s1==s2); System.out.println(s2==s3); } } |
其他饿汉式举例
|
//饿汉式1 class Bank{ //1.私有化构造器 private Bank(){} //2.创建类的对象,同时设置为private的,通过公共的来调用,体现封装性 //4.要求此对象也为static的 private static Bank instance = new Bank(); //3.此公共的方法,必须为static public static Bank getInstance(){ return instance; } } //饿汉式2 class Bank{ //1.私有化构造器 private Bank(){} //2.创建类的对象,同时设置为private的,通过公共的来调用,体现封装性 //4.要求此对象也为static的 private static Bank instance = null; static{ instance = new Bank(); } //3.此公共的方法,必须为static public static Bank getInstance(){ return instance; } } |
1.8 package和import关键字
1.8.1 package
包其实就是目录,特别是项目比较大,java 文件特别多的情况下,我们应该分目录管理,在java 中称为分包管理,包名称通常采用小写。
软件包机制:
①为了解决类的命名冲突问题,在类名前加命名空间(包机制)。
②在java中使用package语句定义包.(单包,复包)。
③package语句只能出现在.java源文件的第一行。
④package定义的格式,通常采用公司域名倒叙方式。
例如:com.bjpowernode.oa.system;
以上包含义:bjpowernode公司开发oa项目,system是oa项目中其中一个模块!
package定义的全格式:公司域名倒叙.项目名.模块名;
⑤完整的类名是带有包名的。
⑥带有package语句的java源文件必须这样编译:javac -d 生成路径 java源文件路径。
⑦运行: java com.bjpowernode.javase.day05.User
|
package com.bjpowernode.javase.day05; public class User{ public static void main(String[] args){ System.out.println("User's main method execute!"); } } |
|
package com.bjpowernode.javase.day05;
public class Test01{
public static void main(String[] args){ User u = new User();
System.out.println(u); //com.bjpowernode.javase.day05.User@c17164 } } |
1.8.2 import
|
package com;
//import语句可以引入其他类. //import语句只能出现在package语句之下,class定义的语句之上。 //import com.bjpowernode.javase.day05.User; import com.bjpowernode.javase.day05.*; //java.lang;软件包下所有类不需要手动导入。系统自动导入. import java.util.Date;
public class Test02{ //入口 public static void main(String[] args){
//User.class找不到. //User u = new User();
com.bjpowernode.javase.day05.User u = new com.bjpowernode.javase.day05.User(); System.out.println(u); //com.bjpowernode.javase.day05.User@c17164
User u1 = new User(); System.out.println(u1);
Object o = new Object(); System.out.println(o); //java.lang.Object@61de33
//SUN提供的日期 Date t = new Date();
System.out.println(t); //Fri Jul 27 15:00:37 CST 2012 } } |
JDK中主要的包介绍
1.java.lang----包含一些Java语言的核心类,如String、Math、Integer、 System和Thread,提供常用功能。
2. java.net----包含执行与网络相关的操作的类和接口。
3. java.io ----包含能提供多种输入/输出功能的类。
4. java.util----包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
5. java.text----包含了一些java格式化相关的类
6. java.sql----包含了java进行JDBC数据库编程的相关类/接口
7. java.awt----包含了构成抽象窗口工具集(abstract window toolkits)的
多个类,这些类被用来构建和管理应用程序的图形用户界
面(GUI)。
8. java.applet----包含applet运行所需的一些类。
总结
1.面向对象思想的落地法则一:
①设计类,并设计类的成员(成员变量&成员方法)
②通过类,来创建类的对象(也称作类的实例化)
③通过“对象.属性” 或“对象.方法”来调用,完成相应的功能
2.创建的多个对象,彼此各自拥有一套类的属性。
当对其中一个对象的属性进行修改时,不会影响到其他对象的属性值。
|
public class Zoo{ public static void main(String args[]){ Animal xb=new Animal(); Animal xh=new Animal(); xb.legs=4; xh.legs=0; System.out.println(xb.legs); //4 System.out.println(xh.legs); //0 xb.legs=2; System.out.println(xb.legs); //2 System.out.println(xh.legs); //0 } } |
3.类的属性(成员变量)
成员变量vs局部变量
相同点:
①遵循变量声明的格式: 数据类型 变量名 = 初始化值
②都有作用域
不同点:
①声明的位置的不同 :
成员变量:声明在类里,方法外;局部变量:声明在方法内,方法的形参部分,代码块内
②关于修饰符:
成员变量的修饰符有四个:public private protected 缺省;
局部变量没有修饰符,与所在的方法修饰符相同。
③初始化值:一定会有初始化值。
成员变量:如果在声明的时候,不显式的赋值,那么不同数据类型会有不同的默认初始化值。
byte short int long ==>0
float double ==>0.0
char ==>空格
boolean ==>false
引用类型变量==>null
局部变量:一定要显式的赋值(局部变量没有默认初始化值)。
④二者在内存中存放的位置不同:
成员变量:存在于堆空间中;局部变量:栈空间中 。
4.关于变量的分类:
①按照数据类型的不同:基本数据类型(8种)& 引用数据类型
②按照声明的位置的不同:成员变量 & 局部变量
5.类的方法:提供某种功能的实现
①实例
|
public void eat(){//方法体} public String getName(){} public void setName(String n){} |
格式:权限修饰符 返回值类型(void:无返回值/具体的返回值) 方法名(形参){}
②关于返回值类型
void:表明此方法不需要返回值
有返回值的方法:在方法的最后一定有return + 返回值类型对应的变量
记忆:void 与return不可以同时出现一个方法内。像一对“冤家”。
③方法内可以调用本类的其他方法或属性,但是不能在方法内再定义方法!


6.类的初始化的内存解析
内存划分的结构:理解的基础上,学会基本的创建的类的对象在内存中的运行。
①栈(stack):局部变量 、对象的引用名、数组的引用名
②堆(heap):new 出来的“东西”(如:对象的实体,数组的实体),含成员变量
③方法区:含字符串常量
④静态域:声明为static的变量
7.面向对象思想的落地法则二:(封装性的思想)
①将类的属性私有化
②提供公共的方法(setter & getter)来实现调用
//声明私有变量 age

浙公网安备 33010602011771号