1.面向对象是相对于面向过程而言的,面向过程是一种谓语与宾语的关系,面向对象的是主语与谓语的关系。
面向对象三大特征:
封装:对外部不可见,可以保护程序中的某些内容;
继承:扩展功能
多态:方法的重载,对象的多态性
类与对象的关系(最重要):
类是对某一类事物的描述,是抽象的、概念上的定义--名词概念;对象是实际存在的该类事物的每一个个体,因而也称为实例(instance)
2.类是对某一类事物的描述,是抽象的、概念上的定义;对象是实际存在的该类事物的每一个个体,因而也称为实例(instance)。面向对象程序设计的重点是类的设计,而不是对象的设计。
类是通过class创建的,一个类创建后不能直接使用,需要产生对象;对象产生的格式有两种:
A.类名 对象名称=null;//申明对象
对象名称=new 类名();//实例化对象
B.类名 对象名称=new 类名();
类图:
在程序的开发中都是以类图的形式进行说明的,对于一个类来说,形式如下:
分为三个层次:
第一个层次:表示类名,类的名称要求首字母大写
第二个层次:表述属性的定义,按照"访问权限 属性名称:属性类型"的格式定义;
第三个层次:表示类中的方法的定义,按照"访问权限 方法名称():方法返回值"的格式定义。
对象的进一步研究
Person per=new Person();
A.申明对象:Person per,栈内存中申明的,与数组一样,数组名称就是保存在栈内存中,只开辟了栈内存的对象是无法使用的,必须有其堆内存的引用才可以使用;
B.实例化对象:new Person(),在堆内存中开辟空间,所有的内容都是默认值;
--String是一个字符串,本身是一个类,就是一个引用数据类型,则此时默认值就是null; --int 是一个数字,本身是一个数,所以是基本数据类型,则此时的默认值是0; 如果进一步划分以上代码,可以表示如下:
Person per=null;//申明对象
Per=new Person()//实例化对象
开发中,数据最好赋一个初值,了解了其分配的关系,就可以为属性赋值,并调用类中的方法。使用格式:
调用属性:对象.属性;
调用方法:对象.方法();
如下:
public class Test {
public static void main(String[] args) {
Person per=new Person();
per.name="zhangsan";
per.age=20;
per.call();
}
}
class Person{
String name;
}
int age; public void call(){ System.out.println("the name is:"+name+",age is"+age); }
一些问题:
a.对象是保存在栈内存中,属性是保存在堆内存中,那么方法保存在哪里的呢?方法是保存在全局代码区之中的,此区中的内容是所有对象共享的。
b.在使用对象的时候,对象必须被实例化之后才可以使用(实例化对象,并不是单单指通过new关键字实现的,只要其有堆内存的空间指向,则表示实例化成功)
c.如果不实例化会出现:java.lang.NullPointerException(空间指向异常)的错误,这是在以后程序开发中会经常遇到的问题,应注意。通常是在引用操作中,如果一个对象没有堆内存的引用,而调用了类中的属性和方法,就会出现这种问题。
d.可以产生多个对象,只要按照一定的格式即可。
类的引用数据类型
所谓的引用数据类型,实际上传递的就是堆内存的使用权,可以同时为一个堆内存空间定义多个栈内存的引用操作。如:per1=per2;
垃圾产生的原理:
public class Test {
public static void main(String[] args) {
Person per1=new Person();
Person per2=new Person();
per1.name="zhangsan";
per1.age=20;
per2.name="xzl";
per2.age=34;
per2=per1;//在这个过程中,per2放弃了堆内存,指向了per1的堆内存,所以此时
per2的堆内存就是垃圾了
System.out.print("per1中的内容---->");
per1.call();
System.out.print("per2中的内容---->");
per2.call();
}
}
class Person{
String name;
int age;
public void call(){
System.out.println("the name is:"+name+",age is"+age);
}
}
对象的比较:“==”与equals();方法的区别
“==”比较两个变量的值是否相等;equals是比较两个对象的内容是否相等。
==实例1:
public class ForTest {
public static void main(String args[]) {
String s1 = new String("abcd");
String s2 = new String("abcd");
if (s1 == s2) {//s1==s3
System.out.println("true");
} else
System.out.println("false");
}
}
输出的结果是:false
实例2:
Equals()方法代码如下:
public class ForTest {
} public static void main(String args[]) { String s1 = new String("abcd"); String s2 = new String("abcd"); if (s1.equals(s2)) {//s1==s3 System.out.println("true"); } else System.out.println("false"); }
输出的结果是:true
封装性
A.目的:为了是为了保护某些属性和方法,不被外部看见,保护程序
B.实现封装:
-为属性封装:private 属性类型 属性名称;
-为方法封装:private 方法返回值 方法名称(参数列表){}
private、public、protected;通常情况下将类的成员变量申明为private,在通过public的方法对这个变量进行访问。对一个变量的操作,一般都有读取和赋值操作,我们分别定义两个方法来实现这两种操作,一个是getXxx(),用来读取这个成员变量的操作,一个是setXxx(),用来对这个成员变量赋值。
访问封装的内容
被封装的属性如果需要被访问,则需要编写setter及getter方法完成,并且类的属性必须都是封装的,这是必须遵守的
例如:有一个属性 private String name;
Setter(设置):public void setName(String n){}
Getter(取得):public String getName();
如下面的代码:
public class Test {
public static void main(String[] args) {
Person per1=new Person();
per1.setName("zhangsan");
per1.setAge(-10);//此时存在一个情况,不符合现实中的需求
per1.call();
}
}
class Person{
String name;
int age;
public void setName(String a){//set方法
name=a;
}
public void setAge(int b){
age=b;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public void call(){
System.out.println("the name is:"+name+",age is"+age);
}
}
上面的代码中只是可以访问封装的内容,但是对属性的赋值还没有验证,需要在set方法中加入验证,注意:一定是在set方法中进行验证。
如下:
if(b>=0 && b
age=b;
}
else age=0;
此时就达到了实际中的要求了。
封装的类图表示
减号表示用private封装了。
构造函数。
只要一有对象实例化则就会调用构造方法。类名 对象=new 类名();//调用的就是一个构造方法;
构造方法的特征
-它具有与类相同的名称
-构造方法的申明处不能有任何返回值类型的申明
-它不能在方法中用return语句返回一个值;
注意:不同于void,如果加上void,则不会自动调用;
构造方法的作用和调用时机:在申明对象时不会调用,当一个类的实例对象刚产生时,这个类的构造方法就会被自动调用,主要作用是为类中的属性进行初始化。
如下面的代码:
实例3:
public class Test {
} public Test() {//如果不写,编译器会自动创建 System.out.println("hello! boy"); } public static void main(String[] args) { new Test(); }
构造方法的重载
和一般的方法重载一样,重载的构造方法具有不同个数或不同类型的参数,编译器就可以根据这一点判断出用new关键字产生对象时,该调用哪一个构造方法,产生对象的格式是:new 类名(参数列表);如下面的例子:
实例4:
public class Test {
int age;
String name;
// 不带参数的构造方法 public Test() { } // 带一个参数的重载构造方法 public Test(String x) { x = name; } // 带两个参数的构造方法 public Test(String x, int y) { name = x; age = y; } // 对测试的数据进行输出的函数 public void test() { System.out.println(name + "'s age is " + age); } public static void main(String[] args) {
Test t1 = new Test();// 如果上面不要不带参数的构造方法,编译器会报错,//因为这时编译器不会自动产生不带参数的构造方法,因为下面已经重载了构造方法 Test t2 = new Test("xzl");
Test t3 = new Test("xzl", 22);
t1.test();
t2.test();
t3.test();
}
}
匿名对象
在Java中,如果一个对象只使用一次,则就可以将其定义为匿名对象;如:new Person().call();所谓的匿名对象就是比之前的对象少了一个栈内存的引用关系;
3.this 关键字的使用,举例如下:
public class Test {
int age;
String name;
// 不带参数的构造方法 public Test() { } // 带一个参数的重载构造方法 public Test(String name) { this.name = name;//加上this后,可以增加代码的可读性 } // 带两个参数的构造方法 public Test(String name, int age) { this.name = name; this.age = age; } // 对测试的数据进行输出的函数 public void test() { System.out.println(name + "'s age is " + age); } public static void main(String[] args) {
Test t1 = new Test();// 如果上面不要不带参数的构造方法,编译器会报错,因为这时编译器不会自动产生不带参数的构造方法,因为下面已经重载了构造方法 Test t2 = new Test("xzl");
Test t3 = new Test("xzl", 22);
t1.test();
t2.test();
t3.test();
}
}
4.Java中垃圾回收分析:
Finalize()是在对象变为垃圾,在被清除内存前调用的,System.gc是直接调用垃圾回收器,清楚垃圾。
可以用finalize()方法和System.gc结合的方式看到Java垃圾回收的效果。实例: public class Test {
public void finalize() {
System.out.println("the gubish is comming!");
}
public static void main(String[] args) {
new Test();
new Test();
new Test();
System.gc();
}
}
静态代码块:
代码块实际上是指用{}括起来的一段代码,根据位置的不同,代码块可以分为四种:普通代码块、构造块、静态代码块、同步代码块,其中同步代码块将在多线程部分讲解。 普通代码块
构造块
把代码块定义在类中,则成为构造类
容
静态代码块
个实例化对象产生,静态代码块只执行一次,静态代码块的主要功能就是为静态属性初始化。
实例:不用main方法,在屏幕上输出“hello world”
虽然可以打印出结果,但是也会出现Exception in thread "main" java.lang.NoSuchMethodError:
Java单态模式和构造方法私有化
构造方法私有化
类的封装性不光体现在对属性的封装上,实际上方法也是可以被封装的,当然,
在方法封装中也包含了对构造方法的封装。例如以下的代码,就是对构造方法进行了封装: 如果现在在外部要进行实例化,在编译的时候就会出现错误:
一个类的构造方法被私有化之后,则只能从其类的内部取得实例化对象,那么此时要考虑的问题就是如何把内部生成的instance对象拿到外部类,这样外部就可以直接通过此对象进行实例化。
正常情况下,instance属性只能通过Singleton类的实例化对象才可以进行调用,如果在没有实例化的时候依然可以取得instance对象,则需要将instance申明为static访问类型。因为使用static申明的变量,可以直接使用类名称进行访问。
为什么要对构造方法私有化呢?为什么不直接通过实例化的形式产生对象?
不管外部申明了多少个Singleton的对象,但是最终结果都是通过getInstance方法取得实例化对象,也就是说,此时s1、s2、s3实际上使用了一个对象的引用:instance
那么这样的设计在设计模式上来讲,属于单态设计模式(单例设计模式):Singleton
如果现在不希望一个类产生过多的对象的话,则必须使用单态设计模式,而且使用单态设计模式在以后的JAVA学习中会经常碰到,因为在JAVA的支持的类库中,大量的采用了此种设计模式。
所谓的单态就是在入口处(构造方法)限制了对象的实例化超早。
在实际的应用中,如Windows中有一个回收站,每一个硬盘中都会有一个回收站,但是事实上只有一个回收站,每个硬盘只是应用的其中的一个实例。
单态设计模式的核心就是将类的构造方法私有化,之后在类的内部产生实例化对象,并通过类的静态方法返回实例化对象。
单态模式的另一个实例:可以统计产生了几个实例
public class Test {
public static void main(String args[]) {
// 这里不能创建Chinese的实例对象,因为构造方法是私有的,但是在Chinese类中可以实例化一个对象,外面只需要调用其中的实例即可
Chinese ch1 = Chinese.getInstance();
Chinese ch2 = Chinese.getInstance();
if (ch1 == ch2)//如果是同一个实例,则输出true System.out.println("true"); else System.out.println("false");
}
}
class Chinese {
static int count = 0;
static String country = "中国";
static Chinese obj = new Chinese();// 可以实例化一个对象,但是一定要申明为static
// 否则会出现不断实例化消耗内存
public static Chinese getInstance() {// 必须是公开和静态的,因为外边不能实例化就要使用
return obj;
}
}
private Chinese() {// 构造方法,用private可以防止外面创建对象 count++; System.out.println(count); } void singOurCountry() { System.out.println(country); }
5.理解main()方法:
·public:表示此方法可以被外部所调用
·static:表示此方法可以由类名直接调用
·void:主方法是程序的起点,所以不需要任何返回值
·main:系统规定好默认调用的方法名称,执行的时候,默认找到main方法名称 ·String args[]:表示是运行时的参数。
String args[]输入的参数,举例如下:
public class Test{
public static void main(String [] args){
} for(String str:args){//循环输出字符数组中的内容 System.out.print(str); } }
输入参数的格式是:java 类名 参数1 参数2...
但是要输入有空格的参数的时候,就需要把有空格的参数用“”括起来才能正确的输入,如下面的例子:
java Test "hello" "xzlmark" world
综合实例,假如需要在启动的时候必须输入三个参数,那么程序代码如下:
public class Test{
public static void main(String [] args){
if(args.length
} System.out.println("输入的参数不足三个,程序退出"); System.exit(1);//非0表示终止JAVA虚拟机 } for(String str:args){//循环输出字符数组中的内容 System.out.print(str); } }
对象数组
所谓对象数组,就是指包含了一组相关的对象,但是在对象数组的使用中要清楚一点:数组一定要先开辟空间,但是因为其是引用数据类型,所以数组里面的每一个对象都是null值,则在使用的时候数组中的每一个对象必须进行实例化操作。
对象数组的申明
·类 对象数组名称[] =new 类[数组长度]
数组本身是属于引用数据类型的,而类本身也是引用数据类型的,所以此时不管是引用还是基本数据类型都可以树勇数组的格式进行申明并使用。
动态实例化:
其实,在之前就开始接触了对象数组,因为String agrs[]就是一个对象数组
Java内部类(嵌套类)
在一个类的内部存在另一个类,则称为内部类。
·在类内部也可以定义另一个类。如果在类Outer的内部在定义一个类Inner,此时类Inner就称为内部类,Outer就称为外部类。
·内部类可申明成public或private。当内部类申明成public或private时,对其访问的限制与成员变量和成员方法相同。
·内部类的定义格式:
标识符 class 外部类名称{
//外部类的成员
标识符 class 内部类的名称{
//内部类的成员
}
}
如下面的内部类例子:
以上的程序中,Inner类作为Outer类的内部类存在,并且在外部类的fun方法中直接实例化内部类的对象并调用print方法。
内部类的特点:
·缺点:正常的一个类操作时,在类中最好只定义属性和方法。如果定义一个类的话,则肯定会破坏程序的结构;
·优点:有时会增加代码,而且复杂度也会增加,使用内部类的最大优点是:可以方便的访问外部类中的私有属性;
但是,以上的内部类,是无法在外部直接调用的,是无法按照外部类的形式使用的。
使用static申明的内部类
如果一个内部类使用static关键字申明,则此内部类就称为外部类,可以直接通过外部类.
但是如果要想访问外部类中的属性,则此属性必须是static访问权限的。
在外部访问内部类
一个内部类除了可以通过外部类访问,也可以直接在其他类中调用,但是调用的格式: ·外部类.内部类 内部类对象 = 外部类实例.new 内部类();
在方法中定义内部类
补充如下:
注意,如果在内部类前面加上static,就相当于是一个外部类,就不能直接访问外部类中的成员变量。
public class ForTest {
public static void main(String args[]) {
Outer outer = new Outer();
outer.test();
}
}
class Outer {
int outer_i = 100;
void test() {
//inner_i=20; 外部类不能直接访问内部类的成员变量 Inner inner = new Inner(); inner.display(); } class Inner { void display() {
System.out.println("outer_i = " + outer_i);// 内部类可以直接访问外部类的成员变量
}
}
}
内部类的访问例子:
public class ForTest {
public static void main(String args[]) {
}
}
class Outer {
int i = 100;
void test() {
}
class Inner {
int i = 2;
void display(int i) {
i++;// // 引用的是display的形式参数 this.i++;// Inner类中的i Outer.this.i++;// Outer中的i } }
}
内部类如何被外部引用:
public class ForTest {
public static void main(String args[]) {
Outer outer = new Outer();//一定要用这种方法才能访问内部类
Outer.Inner inner = outer.new Inner();//要用0ter实例才能这样用 inner.display(10);
}
}
class Outer {
int i = 100;
void test() {
}
class Inner {
int i = 2;
void display(int i) {
}
System.out.println(i++);// // 引用的是display的形式参数 System.out.println(this.i++);// Inner类中的i System.out.println(Outer.this.i++);// Outer中的i } }
输出结果为:
10
2
100
6.内部类--在方法中定义的内部类:
嵌套类并非只能在类中定义,还可以在方法或则几个程序块的范围之内中定义,甚至可以在for循环中定义。在方法中定义的内部类只能访问方法中的final类型的局部变量,用final定义的局部变量相当于一个常量,它的生命周期超出方法运行的生命周期。
1.面向对象是相对于面向过程而言的,面向过程是一种谓语与宾语的关系,面向对象的是主语与谓语的关系。
面向对象三大特征:
封装:对外部不可见,可以保护程序中的某些内容;
继承:扩展功能
多态:方法的重载,对象的多态性
类与对象的关系(最重要):
类是对某一类事物的描述,是抽象的、概念上的定义--名词概念;对象是实际存在的该类事物的每一个个体,因而也称为实例(instance)
2.类是对某一类事物的描述,是抽象的、概念上的定义;对象是实际存在的该类事物的每一个个体,因而也称为实例(instance)。面向对象程序设计的重点是类的设计,而不是对象的设计。
类是通过class创建的,一个类创建后不能直接使用,需要产生对象;对象产生的格式有两种:
A.类名 对象名称=null;//申明对象
对象名称=new 类名();//实例化对象
B.类名 对象名称=new 类名();
类图:
在程序的开发中都是以类图的形式进行说明的,对于一个类来说,形式如下:
分为三个层次:
第一个层次:表示类名,类的名称要求首字母大写
第二个层次:表述属性的定义,按照"访问权限 属性名称:属性类型"的格式定义;
第三个层次:表示类中的方法的定义,按照"访问权限 方法名称():方法返回值"的格式定义。
对象的进一步研究
Person per=new Person();
A.申明对象:Person per,栈内存中申明的,与数组一样,数组名称就是保存在栈内存中,只开辟了栈内存的对象是无法使用的,必须有其堆内存的引用才可以使用;
B.实例化对象:new Person(),在堆内存中开辟空间,所有的内容都是默认值;
--String是一个字符串,本身是一个类,就是一个引用数据类型,则此时默认值就是null; --int 是一个数字,本身是一个数,所以是基本数据类型,则此时的默认值是0; 如果进一步划分以上代码,可以表示如下:
Person per=null;//申明对象
Per=new Person()//实例化对象
开发中,数据最好赋一个初值,了解了其分配的关系,就可以为属性赋值,并调用类中的方法。使用格式:
调用属性:对象.属性;
调用方法:对象.方法();
如下:
public class Test {
public static void main(String[] args) {
Person per=new Person();
per.name="zhangsan";
per.age=20;
per.call();
}
}
class Person{
String name;
}
int age; public void call(){ System.out.println("the name is:"+name+",age is"+age); }
一些问题:
a.对象是保存在栈内存中,属性是保存在堆内存中,那么方法保存在哪里的呢?方法是保存在全局代码区之中的,此区中的内容是所有对象共享的。
b.在使用对象的时候,对象必须被实例化之后才可以使用(实例化对象,并不是单单指通过new关键字实现的,只要其有堆内存的空间指向,则表示实例化成功)
c.如果不实例化会出现:java.lang.NullPointerException(空间指向异常)的错误,这是在以后程序开发中会经常遇到的问题,应注意。通常是在引用操作中,如果一个对象没有堆内存的引用,而调用了类中的属性和方法,就会出现这种问题。
d.可以产生多个对象,只要按照一定的格式即可。
类的引用数据类型
所谓的引用数据类型,实际上传递的就是堆内存的使用权,可以同时为一个堆内存空间定义多个栈内存的引用操作。如:per1=per2;
垃圾产生的原理:
public class Test {
public static void main(String[] args) {
Person per1=new Person();
Person per2=new Person();
per1.name="zhangsan";
per1.age=20;
per2.name="xzl";
per2.age=34;
per2=per1;//在这个过程中,per2放弃了堆内存,指向了per1的堆内存,所以此时
per2的堆内存就是垃圾了
System.out.print("per1中的内容---->");
per1.call();
System.out.print("per2中的内容---->");
per2.call();
}
}
class Person{
String name;
int age;
public void call(){
System.out.println("the name is:"+name+",age is"+age);
}
}
对象的比较:“==”与equals();方法的区别
“==”比较两个变量的值是否相等;equals是比较两个对象的内容是否相等。
==实例1:
public class ForTest {
public static void main(String args[]) {
String s1 = new String("abcd");
String s2 = new String("abcd");
if (s1 == s2) {//s1==s3
System.out.println("true");
} else
System.out.println("false");
}
}
输出的结果是:false
实例2:
Equals()方法代码如下:
public class ForTest {
} public static void main(String args[]) { String s1 = new String("abcd"); String s2 = new String("abcd"); if (s1.equals(s2)) {//s1==s3 System.out.println("true"); } else System.out.println("false"); }
输出的结果是:true
封装性
A.目的:为了是为了保护某些属性和方法,不被外部看见,保护程序
B.实现封装:
-为属性封装:private 属性类型 属性名称;
-为方法封装:private 方法返回值 方法名称(参数列表){}
private、public、protected;通常情况下将类的成员变量申明为private,在通过public的方法对这个变量进行访问。对一个变量的操作,一般都有读取和赋值操作,我们分别定义两个方法来实现这两种操作,一个是getXxx(),用来读取这个成员变量的操作,一个是setXxx(),用来对这个成员变量赋值。
访问封装的内容
被封装的属性如果需要被访问,则需要编写setter及getter方法完成,并且类的属性必须都是封装的,这是必须遵守的
例如:有一个属性 private String name;
Setter(设置):public void setName(String n){}
Getter(取得):public String getName();
如下面的代码:
public class Test {
public static void main(String[] args) {
Person per1=new Person();
per1.setName("zhangsan");
per1.setAge(-10);//此时存在一个情况,不符合现实中的需求
per1.call();
}
}
class Person{
String name;
int age;
public void setName(String a){//set方法
name=a;
}
public void setAge(int b){
age=b;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public void call(){
System.out.println("the name is:"+name+",age is"+age);
}
}
上面的代码中只是可以访问封装的内容,但是对属性的赋值还没有验证,需要在set方法中加入验证,注意:一定是在set方法中进行验证。
如下:
if(b>=0 && b
age=b;
}
else age=0;
此时就达到了实际中的要求了。
封装的类图表示
减号表示用private封装了。
构造函数。
只要一有对象实例化则就会调用构造方法。类名 对象=new 类名();//调用的就是一个构造方法;
构造方法的特征
-它具有与类相同的名称
-构造方法的申明处不能有任何返回值类型的申明
-它不能在方法中用return语句返回一个值;
注意:不同于void,如果加上void,则不会自动调用;
构造方法的作用和调用时机:在申明对象时不会调用,当一个类的实例对象刚产生时,这个类的构造方法就会被自动调用,主要作用是为类中的属性进行初始化。
如下面的代码:
实例3:
public class Test {
} public Test() {//如果不写,编译器会自动创建 System.out.println("hello! boy"); } public static void main(String[] args) { new Test(); }
构造方法的重载
和一般的方法重载一样,重载的构造方法具有不同个数或不同类型的参数,编译器就可以根据这一点判断出用new关键字产生对象时,该调用哪一个构造方法,产生对象的格式是:new 类名(参数列表);如下面的例子:
实例4:
public class Test {
int age;
String name;
// 不带参数的构造方法 public Test() { } // 带一个参数的重载构造方法 public Test(String x) { x = name; } // 带两个参数的构造方法 public Test(String x, int y) { name = x; age = y; } // 对测试的数据进行输出的函数 public void test() { System.out.println(name + "'s age is " + age); } public static void main(String[] args) {
Test t1 = new Test();// 如果上面不要不带参数的构造方法,编译器会报错,//因为这时编译器不会自动产生不带参数的构造方法,因为下面已经重载了构造方法 Test t2 = new Test("xzl");
Test t3 = new Test("xzl", 22);
t1.test();
t2.test();
t3.test();
}
}
匿名对象
在Java中,如果一个对象只使用一次,则就可以将其定义为匿名对象;如:new Person().call();所谓的匿名对象就是比之前的对象少了一个栈内存的引用关系;
3.this 关键字的使用,举例如下:
public class Test {
int age;
String name;
// 不带参数的构造方法 public Test() { } // 带一个参数的重载构造方法 public Test(String name) { this.name = name;//加上this后,可以增加代码的可读性 } // 带两个参数的构造方法 public Test(String name, int age) { this.name = name; this.age = age; } // 对测试的数据进行输出的函数 public void test() { System.out.println(name + "'s age is " + age); } public static void main(String[] args) {
Test t1 = new Test();// 如果上面不要不带参数的构造方法,编译器会报错,因为这时编译器不会自动产生不带参数的构造方法,因为下面已经重载了构造方法 Test t2 = new Test("xzl");
Test t3 = new Test("xzl", 22);
t1.test();
t2.test();
t3.test();
}
}
4.Java中垃圾回收分析:
Finalize()是在对象变为垃圾,在被清除内存前调用的,System.gc是直接调用垃圾回收器,清楚垃圾。
可以用finalize()方法和System.gc结合的方式看到Java垃圾回收的效果。实例: public class Test {
public void finalize() {
System.out.println("the gubish is comming!");
}
public static void main(String[] args) {
new Test();
new Test();
new Test();
System.gc();
}
}
静态代码块:
代码块实际上是指用{}括起来的一段代码,根据位置的不同,代码块可以分为四种:普通代码块、构造块、静态代码块、同步代码块,其中同步代码块将在多线程部分讲解。 普通代码块
构造块
把代码块定义在类中,则成为构造类
容
静态代码块
个实例化对象产生,静态代码块只执行一次,静态代码块的主要功能就是为静态属性初始化。
实例:不用main方法,在屏幕上输出“hello world”
虽然可以打印出结果,但是也会出现Exception in thread "main" java.lang.NoSuchMethodError:
Java单态模式和构造方法私有化
构造方法私有化
类的封装性不光体现在对属性的封装上,实际上方法也是可以被封装的,当然,
在方法封装中也包含了对构造方法的封装。例如以下的代码,就是对构造方法进行了封装: 如果现在在外部要进行实例化,在编译的时候就会出现错误:
一个类的构造方法被私有化之后,则只能从其类的内部取得实例化对象,那么此时要考虑的问题就是如何把内部生成的instance对象拿到外部类,这样外部就可以直接通过此对象进行实例化。
正常情况下,instance属性只能通过Singleton类的实例化对象才可以进行调用,如果在没有实例化的时候依然可以取得instance对象,则需要将instance申明为static访问类型。因为使用static申明的变量,可以直接使用类名称进行访问。
为什么要对构造方法私有化呢?为什么不直接通过实例化的形式产生对象?
不管外部申明了多少个Singleton的对象,但是最终结果都是通过getInstance方法取得实例化对象,也就是说,此时s1、s2、s3实际上使用了一个对象的引用:instance
那么这样的设计在设计模式上来讲,属于单态设计模式(单例设计模式):Singleton
如果现在不希望一个类产生过多的对象的话,则必须使用单态设计模式,而且使用单态设计模式在以后的JAVA学习中会经常碰到,因为在JAVA的支持的类库中,大量的采用了此种设计模式。
所谓的单态就是在入口处(构造方法)限制了对象的实例化超早。
在实际的应用中,如Windows中有一个回收站,每一个硬盘中都会有一个回收站,但是事实上只有一个回收站,每个硬盘只是应用的其中的一个实例。
单态设计模式的核心就是将类的构造方法私有化,之后在类的内部产生实例化对象,并通过类的静态方法返回实例化对象。
单态模式的另一个实例:可以统计产生了几个实例
public class Test {
public static void main(String args[]) {
// 这里不能创建Chinese的实例对象,因为构造方法是私有的,但是在Chinese类中可以实例化一个对象,外面只需要调用其中的实例即可
Chinese ch1 = Chinese.getInstance();
Chinese ch2 = Chinese.getInstance();
if (ch1 == ch2)//如果是同一个实例,则输出true System.out.println("true"); else System.out.println("false");
}
}
class Chinese {
static int count = 0;
static String country = "中国";
static Chinese obj = new Chinese();// 可以实例化一个对象,但是一定要申明为static
// 否则会出现不断实例化消耗内存
public static Chinese getInstance() {// 必须是公开和静态的,因为外边不能实例化就要使用
return obj;
}
}
private Chinese() {// 构造方法,用private可以防止外面创建对象 count++; System.out.println(count); } void singOurCountry() { System.out.println(country); }
5.理解main()方法:
·public:表示此方法可以被外部所调用
·static:表示此方法可以由类名直接调用
·void:主方法是程序的起点,所以不需要任何返回值
·main:系统规定好默认调用的方法名称,执行的时候,默认找到main方法名称 ·String args[]:表示是运行时的参数。
String args[]输入的参数,举例如下:
public class Test{
public static void main(String [] args){
} for(String str:args){//循环输出字符数组中的内容 System.out.print(str); } }
输入参数的格式是:java 类名 参数1 参数2...
但是要输入有空格的参数的时候,就需要把有空格的参数用“”括起来才能正确的输入,如下面的例子:
java Test "hello" "xzlmark" world
综合实例,假如需要在启动的时候必须输入三个参数,那么程序代码如下:
public class Test{
public static void main(String [] args){
if(args.length
} System.out.println("输入的参数不足三个,程序退出"); System.exit(1);//非0表示终止JAVA虚拟机 } for(String str:args){//循环输出字符数组中的内容 System.out.print(str); } }
对象数组
所谓对象数组,就是指包含了一组相关的对象,但是在对象数组的使用中要清楚一点:数组一定要先开辟空间,但是因为其是引用数据类型,所以数组里面的每一个对象都是null值,则在使用的时候数组中的每一个对象必须进行实例化操作。
对象数组的申明
·类 对象数组名称[] =new 类[数组长度]
数组本身是属于引用数据类型的,而类本身也是引用数据类型的,所以此时不管是引用还是基本数据类型都可以树勇数组的格式进行申明并使用。
动态实例化:
其实,在之前就开始接触了对象数组,因为String agrs[]就是一个对象数组
Java内部类(嵌套类)
在一个类的内部存在另一个类,则称为内部类。
·在类内部也可以定义另一个类。如果在类Outer的内部在定义一个类Inner,此时类Inner就称为内部类,Outer就称为外部类。
·内部类可申明成public或private。当内部类申明成public或private时,对其访问的限制与成员变量和成员方法相同。
·内部类的定义格式:
标识符 class 外部类名称{
//外部类的成员
标识符 class 内部类的名称{
//内部类的成员
}
}
如下面的内部类例子:
以上的程序中,Inner类作为Outer类的内部类存在,并且在外部类的fun方法中直接实例化内部类的对象并调用print方法。
内部类的特点:
·缺点:正常的一个类操作时,在类中最好只定义属性和方法。如果定义一个类的话,则肯定会破坏程序的结构;
·优点:有时会增加代码,而且复杂度也会增加,使用内部类的最大优点是:可以方便的访问外部类中的私有属性;
但是,以上的内部类,是无法在外部直接调用的,是无法按照外部类的形式使用的。
使用static申明的内部类
如果一个内部类使用static关键字申明,则此内部类就称为外部类,可以直接通过外部类.
但是如果要想访问外部类中的属性,则此属性必须是static访问权限的。
在外部访问内部类
一个内部类除了可以通过外部类访问,也可以直接在其他类中调用,但是调用的格式: ·外部类.内部类 内部类对象 = 外部类实例.new 内部类();
在方法中定义内部类
补充如下:
注意,如果在内部类前面加上static,就相当于是一个外部类,就不能直接访问外部类中的成员变量。
public class ForTest {
public static void main(String args[]) {
Outer outer = new Outer();
outer.test();
}
}
class Outer {
int outer_i = 100;
void test() {
//inner_i=20; 外部类不能直接访问内部类的成员变量 Inner inner = new Inner(); inner.display(); } class Inner { void display() {
System.out.println("outer_i = " + outer_i);// 内部类可以直接访问外部类的成员变量
}
}
}
内部类的访问例子:
public class ForTest {
public static void main(String args[]) {
}
}
class Outer {
int i = 100;
void test() {
}
class Inner {
int i = 2;
void display(int i) {
i++;// // 引用的是display的形式参数 this.i++;// Inner类中的i Outer.this.i++;// Outer中的i } }
}
内部类如何被外部引用:
public class ForTest {
public static void main(String args[]) {
Outer outer = new Outer();//一定要用这种方法才能访问内部类
Outer.Inner inner = outer.new Inner();//要用0ter实例才能这样用 inner.display(10);
}
}
class Outer {
int i = 100;
void test() {
}
class Inner {
int i = 2;
void display(int i) {
}
System.out.println(i++);// // 引用的是display的形式参数 System.out.println(this.i++);// Inner类中的i System.out.println(Outer.this.i++);// Outer中的i } }
输出结果为:
10
2
100
6.内部类--在方法中定义的内部类:
嵌套类并非只能在类中定义,还可以在方法或则几个程序块的范围之内中定义,甚至可以在for循环中定义。在方法中定义的内部类只能访问方法中的final类型的局部变量,用final定义的局部变量相当于一个常量,它的生命周期超出方法运行的生命周期。