java 编程思想 笔记


第二章 一切都是对象 

只有引用,无对象(记住,你能做到的只能是操作对象的引用,而非对象。)

如:  Test a  = b;   赋值的是引用,绝非对象(你没有机会操作对象)


2.2.2  java 基本类型 固定大小,与硬件平台无关。

char 16bits

java无sizeof

无 unsigned

boolean 仅能够赋值为 true或false   0,1 或者其他整数会报错。


基本类型具有的包装器类,使得可以在堆中创建一个对象,表示对应的基本类型


作用域:

{

int  x=1;

    {

       int x=2;

   }

}

C/c++中是可以的,但在java中上面写法是不允许的,java认为这样写会导致程序混乱。


java 中使用 术语“方法” 来替代 “函数”。


名为a的对象,消息是f()

a.f();

发送消息给对象。


传递参数: 方法的参数列表指定要传递给方法什么样的信息。

这些信息像java中的其他信息一样,采用的都是对象形式。

java中任何传递对象的场合,传递的实际上是引用。     传递: 对象 的 引用。 传参,本质传递的是对象。 通过引用来传递对象。

java 一切皆是对象。    操作对象 使用的是引用


使用其他构件: 使用某一个特定的类, 使用import指示编译器导入一个包,即类库,java所有代码都必须写在类里。

大多时候使用与编译器附在一起的java标准类库,就不必写域名了。如 import java.util.ArrayList;

或更常用: import java.util.*;


static:

通常,创建类时,是在描述那个类的对象的外观和行为, 除非new创建对象,否则未获得任何对象。(java一切皆对象)

两种情形:

1.希望只分配单一存储空间。

2. 方法不与类的任何对象关联在一起。

使用static关键字:

把static放在定义前:

class Test{

static int i=1;     //  可以将 字段或方法 设定为static。 代码生成了一个static字段。

int  j; 

}


尽管当static作用于某个字段时,肯定会改变数据的创建方式。

但,将static 作用于某个方法, 却仅仅是在不创建任何 对象的前提下就可以调用它



类库:

请参考 jdk文档,即类库的说明文档。


有一个类会自动被导入到每个java文件中: java.lang

java.lang 有些什么呢?请参考 上面的jdk说明文档。


jdk文档左侧栏的上半部分是 包。

点击上半部分中 的java.lang.

左侧栏的下半部会显示 该包中的 : 接口,类,枚举,异常,错误。。。



文档(注释文档,说明文档):

javadoc 提取注释。

有一些注释语法:

1. 所有javadoc 都在“ /** ” 注释中。

2. 方式 有两种: ”嵌入式的html“ 或者 “文档标签”


注释的对象(元素):

    类, 域, 方法。

//: Test.java
/** A class comment */
public class Test{
    /** A field comment */
    public int i;
    /** A method comment */
    public void f(){}
}  ///:~


嵌入式html:  主要是为了 进行 格式化显示。

/**
* You can even insert a list:
*
    *
  1. Item one *
  2. Item two *
*/


文档标签:

分类:

 独立文档标签

@see classname
@see fully-qualified-classname#name

产生的文档的显示效果 等同 HTML的超链接:

会在生成的文档中加入一个具有超链接的 “See Also”


行内文档标签

{@docRoot}
{@link package.class#member label}
用于行内,用label作为超链接文本,不用“See Also”

示例:

//: Test.java
/** 
* @author  xxx
* A example case for javadoc.
*/
/** @see TestOther */
public class Test
{
	/** A field comment */
	private int i;
	/** A method comment */
	public void fun(){}
}

javadoc Test.java

类 Test

    java.lang.Object
        Test


    public class Test
    extends java.lang.Object

    另请参阅:
        TestOther

        构造器概要
        构造器  构造器和说明
        Test() 
        方法概要
        方法  限定符和类型 	方法和说明
        void 	fun()
        A method comment
            从类继承的方法 java.lang.Object
            clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

        构造器详细资料
            Test

            public Test()

        方法详细资料
            fun

            public void fun()

            A method comment



作业:

自己动手写存在的问题:

1. 仍然没有习惯类,在类的定义成员的地方,当成C函数似的,又定义了一个类。

   类中能定义其他类的地方在方法中。

public  class Test
{
    class DataOnly
    {
         int i;
     }

     public static void main(){
        DataOnly dao = new DataOnly();
        dao.i = 5;
        System.out.println("i="+i);
    }
}
1.  DataOnly 定义不能写在类成员的地方

2.  println 打印时候,要写全类: dao.i , 这是C的坏习惯。忘记加类名。


一切都是对象: 

相比C或c++,java是一种"面向对象"的设计语音。

对象是基本元素。 java就是对象。


用引用 操纵对象:

操纵内存的方式:  在java里,一切都被视为对象,但操纵的标识符实际上是对象的一个“引用”。

理解: 对象 -  引用。 对象存在于内存中,且只有一个。  对象的引用可以有多个。

对象存在在内存中。   多个引用来使用这块内存(对象)。


如想操纵一个String对象,则可以创建一个String 引用。

看来: 想操纵一个对象或内存的必要条件是 首先要有个引用:

String s;  所创建的只是引用,并不是对象。  对象离不开new。


理解了引用,对对象的创建就好理解了:  new




第3章  操作符 

静态导入: import static

http://kanpiaoxue.iteye.com/blog/1977862

静态导入,意味着 想导入类的函数,而不是类本身。

如果使用了静态导入,使用时就要省略包名,否则一样会报错的。即,静态导入不是import的超集,而是不同层次的导入。

import 导入: 使用时要带包名。

import static 导入: 使用时,不要写包名,否则报错。


操作符:

几乎所有操作符都只能操作基本类型。

例外是: =  ==  != 这三个操作符可以操作所有的对象(错,其实是引用,怎么可能操作对象呢)。

String类还支持 +  +=


”对象“ ”赋值“操作:

对一个对象进行操作时,真正操作的是对象的引用。

所以,将一个”对象“赋值给另一个”对象“,实际上,是将引用赋值给另一个引用

可以这么认为,引用是作为一种类型存在的,对象是存在于内存中的。

所以,上面的赋值操作,准确的说(实际上)是 引用的赋值操作。 永远无法直接操作对象本身,只存在引用。

方法调用中的别名现象:

将一个对象传递给方法时,同样传递的是对象的一个引用。 (类似于指针)




        AClassType a1 = new AClassType();
        AClassType a2 = new AClassType();

        System.out.println(a1 == a2);

我们知道,结果是false。

因为上面比较的是引用,很明显是两个不同的引用。



函数传参:

在C语言中,函数传参是复制参数的一个副本。

但是在java中,如果参数是对象,但实际上只是传递了一个引用(你永远无法直接操作对象本身,它在内存,垃圾回收机制也是扫描是否有引用。)

所以,在函数体中,如果修改了引用,是会修改函数之外的对象的。


Random 用法:

Random rand = new Random(47);

int j = rand.nextInt(100) +1;

随即数,注定了它不可能是个静态方法,所以,别忘记了 new一个Random() 然后再使用 刚才new的这个对象来产生随即数。


比较操作:

首先,仍然是那句话,你所直接操作的是对象的引用。

比较操作时,比较的也是引用 : ==

如果希望比较对象,而不是引用,那么你就只能自己来实现了,所以呢,既然是自己实现,那么一般是函数,equals。

总结: 直接比较是引用  ==

           对象内容的比较  equals(需要自己去实现equals)


短路:

test()  &&  test2()  &&  test3();

找到了false就不再进行下去。

&& 操作本来就是 1  不起作用, 0 起作用。 如果找到了 0  ,就不再找


常量:

十六进制表示 适用所有整数类型 int  long short等

编译器通常会将指数作双精度double处理

float  f = 1e-43f;  后面的f是必须的。



第四章: 控制执行流程

迭代:  while  do-while   for

while:  循环刚开始时, 会 计算一次 表达式的值; 在下一次迭代开始前  再次计算布尔表达式的值。

即,每次循环开始前,先计算布尔表达式的值。

do-while 和while的唯一区别是:do-while 中的语句   会至少执行一次。 即使,布尔表达式第一次就被计算为false。

for: 在第一次迭代前要进行初始化; 然后进行条件测试; 每次循环结束,执行一次步进。

       空for循环:  里面是两个分号,而不是三个 亲!

       for(;;){}

for语句的 初始化部分,可以拥有任意数量的 具有相同类型的变量定义。


foreach语法:

仍然是for,使用形式不同。

foreach语法用于数组和容器。表示不必创建int变量去对访问的序列进行技术,foreach自动产生每一项。

foreach是一个简洁的自动语法。 它的含义如上描述。即,使用foreach语法,就代表你希望按照上面的描述来访问序列的每一项。

f[10]....

for(float x: f)

  System.out.print(x);

上面foreach语法,就表示 将自动对每一项动作。 它是一种简洁的表达语法。

而对于这种: for(int i=0; i<100; i++){}

foreach 语法将不起作用。 因为它并非是一个序列(数组或容器)对象,它只是一个数而已,无法产生foreach的含义,对序列的每一项。。。

foreach适用于一个对象表示的范围,而不是数值表示的范围。


无条件 分支: return break continue


break

用于强行退出,不再执行循环中剩余的语句。


continue

停止执行 当前的迭代,然后退回循环起始处,开始下一次迭代。


goto: java中没有goto!然而java能完成一些类似的操作。使用了相同的机制: 标签。

标签后面有冒号的标识符

label:

xxx:

abc:

标签起作用的地方是 刚好在迭代语句之前。

标签和迭代之间置入任何语句都不好。


在迭代开始之前 设置标签的理由是:

由于break;continue只中断当前循环,若随标签一起使用,可以跳到标签所在的地方。


关于递增表达式是否执行:

break 不管带不带标签都不执行递增 : i++

continue 与带不带标签也无直接关系: continue带标签,但若只是一层迭代即只是通过标签跳出了一层迭代,那么递增仍然会执行。(已测试)

可 是如果因为使用了标签,continue跳出了两层迭代,那么后面的迭代是不执行的。 (已测试)

import static com.xxx.tij.myutils.Print.*;

public class Test
{
	public static void main(String[] args){
		int i = 0;
		outer:
//			for(;;){
		for(;;i++){
			println("i="+i);
			if(i ==2){
			println("continue outer");
			continue outer;
			}
		}
//		}

	
/*		int i=0;
		outer:
		for(;true;){
			inner:
			for(;i<10;i++){
				println("i="+i);
				if(i == 2){
					println("continue");
					continue;
				}
				if(i == 3){
					println("break");
					i++; //
					break;
				}
				if(i == 7){
					println("continue outer");
					//i++;
					continue outer;
				}
				if(i == 8){
					println("break outer");
					break outer;
				}
				for(int k = 3; k<5; k++){
					if(k==3){
						println("continue inner");
						continue;
					}
				}
			}
		}*/
	}
}


第五章  初始化 与 清理

函数重载: 构造器是要求java支持函数重载的一个原因。


this关键字:

函数: 发送消息给对象。

a.peel(1);

b.peel(2);

方法调用的内部形式:

Banana.peel(a, 1);

Banana.peel(b, 1);

编译器 暗自把 函数 所操作对象 的引用,作为第一个参数传递给peel()

由于这个引用是 编译器“偷偷” 传入的,所有没有标识符。但,有个专门的关键字: this。


通常(例外的情况是this还可用作构造器),this只能在 方法 内部使用,表示 调用方法的那个对象 的引用。记住,this是怎么来的:

是编译器暗自把 调用函数的对象的引用给当做函数的第一个参数传进来的,因为没有标识符,才叫做this,

当然,只能在 函数里使用了,表示的就是调用函数的那个对象的引用。

this使用:

1. return this;

2. 将自身 传递给外部方法: 即,在函数中调用外部函数,将自身作为参数传递给外部函数时,使用this

3. this.成员

4. 特殊: 构造器中调用构造器。

    通常情况下this代表 函数中的 调用该函数的对象。 但是如果this后面带括号和参数。

   那么就变成了构造器调用。

   this();构造器的调用必须是 另一构造器调用 它,普通函数不能调用 this形式的构造器。

  this形式的构造器调用,只能调用一次,且必须在起始处。


static方法: 是没有this的方法。

static方法不是面向对象的。它确实有些全局函数的含义, 如果在代码中出现大量static就要重新考虑设计了。


finalize 是随着垃圾回收器一起发生,而垃圾回收器不保证一定会发生,因此,不要指望finalize进行很及时的清理操作。

但是,一些对清理的时间没有要求,但是 清理条件可以在finalize中进行验证,即,希望只要finalize发生,就一定要先验证是否符合条件。

可以在finalize中进行,对象终结的条件进行验证:

public class Test
{
	public static void main(String[] args){
		Book book1 = new Book(1);
		//book1.in();
		for(int i=0; i< 10; i++){
		new Book(i);
		}
		System.gc();
		for(int j=0; j< 1000; j++){
			new Book(j);
		}
	}
}

class Book
{
	boolean out = false;
	final int id;
	public Book(int i){
		out = true;
		id = i;
	}

	void in(){
		out = false;
	}

	protected void finalize(){
		if(out){
			System.out.println("error:"+id);
		}
	}
}
注: 即使调用System.gc()垃圾回收也不是一定执行,只要空间还充足。(已测试)


初始化:

局部变量,如果忘记初始化,编译器会报错提示: 可能尚未初始化变量。


类成员变量:

1. 可以不初始化,则基本类型会有默认值(其实是通过new时,将整个块清零得到的)

   对象引用的初值是null


初始化:

1) 类成员可以不初始化,默认值

2)在定义类成员的地方赋值,这样每个类的对象,都含义相同的初值。

3)构造器初始化,相比(2)更灵活。

     但是,构造器初始化不是必须的,因为编译器总会保证使用前,类的成员已经得到初始化 通过步骤(1)或(2)。 (2)(3)是非必须的。(1)是自动的。


成员变量初始化顺序

变量定义的顺序决定了初始化的顺序,即使散布于方法定义之间。

变量总是在任何方法被调用前已经得到了初始化,包括构造器,这也同样证明了 构造器中的初始化不是必须的


static静态变量初始化:

static关键字只能作用于 成员。

无论创建多少个对象,static域都只占用一份存储区域。 确切说的共享。

一个对象修改了它的static域,其他对象的static域也会变成修改后的。 所有static最好用于一改全改的情况。


静态成员在 类载入过程中初始化,且只进行一次初始化。

然后是普通成员进行初始化。


数组:(数组的使用 == 对象)  操作的同样是引用,而不能直接操作数组的值本身。 

type[] array; 编译器不允许指定数组的大小。是因为,现在拥有的是数组的引用,非数组本身。

既然是引用,那么没有必要限定数组的大小。

数组初始化:

1) 特殊的初始化: 在定义数组的地方出现,由一对花括号括起来的值组成:

   int[] a = {1, 2, 3, 4, 5};   它仍然是new出来的。  还是那句话,因为这里操作的是引用 ,引用指向的内存是new的。

因为是引用,所以 可以给引用赋值: int[] a2;   a2 = a1;

2) 由于数组的元素是new出来的。 动态创建的。 所以数组的大小可以在运行时指定: 如rand.nextInt(xx);

3) 同其他对象一样,最好在定义时 进行初始化:  写法:

new  int[123];   看来,数组这种“对象” 的定义形式是:(假设这里元素是int类型)   int[xxx],则分配对象用 new int[xxx];

就像 class Test , 对象分配用 new Test();

数组类型,有其不同点,就是 分配了其自身的空间后,还要为其元素(它的元素可以是引用(引用指向的对象仍然需要重新分配空间,即你永远只能操作引用,对象仍然需要new),或基本类型)进行初始化。 

4)初始化列表的两种形式:

   第一种:上面提到过的(1)的形式:Integer[] a = {new Integer(1), 3};

第二种: Integer[] b = new Integer[] { new Integer(1), 3 };

就像上面提到过的1)的初始化列表的形式受限,它只能用于数组定义处。

可以在任何地方使用第二种形式


数组,无论元素是基本类型还是对象,都有一个固有 成员,length。它不是函数。


可变参数列表:

关键是在传参时,要像可变参数列表。 第二种初始化列表的形式,一定程度上支持了可变参数列表。

java的可变参数列表,实现的基础是  上面的数组的 第二种初始化列表形式。

因此,可在可变参数列表的 函数中,使用 foreach进行迭代。(因为 java会把可变参数列表,实现为数组)

	static void fun(Object... args){
		for(Object e: args)
			print(e);
	}







你可能感兴趣的:(java)