在java程序中,一個java源文件稱爲編譯單元,以.java後綴命名。編譯單元內能夠有一個public類,類名必須與文件名相同。注意:每一個編譯單元只能有一個public類。java
在C#中,咱們用命名空間namespace來組織類庫,用using關鍵字導入某個命名空間。Java中有一樣的概念成爲包,關鍵字是package,使用import關鍵字導入包。ide
1.package:
類庫就是一組文件,每一個文件都有一個public類,以及任意數量的非public類。package語句用來指定當前文件所屬的類庫,它必須放在文件開始,除註釋外的第一行代碼。例如:package com.cathy.dto;函數
2.import:
若是想使用某個包中的類,須要使用import導入對響應包的引用。若是導入包中的多個類,可使用import.cathy.dto.*;測試
3.訪問修飾符:this
有一點須要注意:在C#中,類中的成員若是不添加訪問修飾符默認是private;可是在Java中若是不提供任何訪問修飾詞,默認是包訪問權限,處於同一個編譯單元中的全部類彼此之間都是自動可訪問的。
spa
1.基本類型做爲參數傳遞
八種基本數據類型(byte,short,int,long,double,float,char,boolean)做爲參數傳遞時,傳遞的是值的拷貝。因此,方法中任何操做都不會修改原值。設計
public class PrimitiveDemo { public static void main(String[] args) { int num = 10; change(num); System.out.println("main() a=" + num);//10 } private static void change(Integer a) { System.out.println("1 change() a=" + a); a = 20; System.out.println("2 change() a=" + a); } }
運行結果:code
1 change() a=10
2 change() a=20
main() a=10
2.對象參數傳遞引用的拷貝
這個地方,在看《JAVA核心技術I》的時候,做者說的是「JAVA程序設計語言老是按值傳遞」,這個描述感受不是太贊同。看了後面的描述:「方法獲得的是對象引用的拷貝,對象引用及其餘拷貝都同時引用同一對象」。大致和我理解的意思是一致的,也就不糾結說法了。
爲方便測試,首先咱們定義一個類Book:對象
class Book { private int price; public void setPrice(int price) { this.price = price; } public Book(int price) { this.price = price; } @Override public String toString() { return super.toString() + "[price=" + price + "]"; } }
當爲對象類型賦值時,其實是將兩個對象指向了同一個引用,天然也就很容易修改引用對象的屬性了。blog
public class ObjectDemo { public static void main(String[] args) { Book book = new Book(10); System.out.println("①" + book.toString()); change(book); System.out.println("③" + book.toString()); } private static void change(Book book) { book.setPrice(20); System.out.println("②change()" + book); } } 運行結果: ①Book@7440e464[price=10] ②change()Book@7440e464[price=20] ③Book@7440e464[price=20]
從運行結果能夠看出:change()方法中的book參數確實和原對象指向了同一地址,也就是說在Java中對象做爲參數傳遞時,其實是把對象在內存中的地址拷貝傳給了參數。這樣一來,對參數對象book的修改也就修改了原對象。
到這裏我就想,兩個對象指向的內存地址是同樣的,那會不會對象做爲參數時,直接傳遞的就是該對象的引用呢?若是這樣的話,咱們修改一下參數book的指向,看看會不會影響原有對象的引用。
public class ObjectDemo2 { public static void main(String[] args) { Book b1=new Book(10); Book b2=new Book(20); System.out.println("before swap" + b1.toString()+b2.toString()); swap(b1,b2); System.out.println("after swap" + b1.toString()+b2.toString()); } private static void swap(Book pb1, Book pb2) { Book temp = pb1; pb1 = pb2; pb2 = temp; System.out.println("swap() pb1 " + pb1); System.out.println("swap() pb2 " + pb2); pb1.setPrice(100); pb2.setPrice(200); } }
運行結果:
before swapBook@7440e464[price=10] Book@49476842[price=20] swap() pb1 Book@49476842[price=20] swap() pb2 Book@7440e464[price=10] after swapBook@7440e464[price=200] Book@49476842[price=100]
能夠看到b1和b2引用的對象並無變化,交換的只是拷貝的引用pb1和pb2的地址。
提及構造函數你們一點都不陌生,但有幾點要注意的地方:
1.僅當沒有提供任何構造器的時候,系統纔會默認提供一個無參構造器。
2.構造函數能夠調用另外一個構造函數,可是必須遵照如下幾個規則:
* 構造函數調用必須位於第一行;
* 構造函數只能被調用一次;
* 不能在構造函數之外的任何位置調用構造函數。
public class Person { private String name; private Integer age; public Person(String name) { this.name = name; } public Person(String name, Integer age) { this(name); this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } public static void main(String[] args) { Person p = new Person("a", 11); System.out.println(p); } }
3.初始化順序:先初始化變量,後調用構造函數。
在同一個類中,變量的初始化是和定義的前後順序一致的。不過,即便變量定義在構造函數的後面,仍然會先初始化全部變量,而後才執行構造函數。
public class Order { OrderDetail d1 = new OrderDetail(100); OrderDetail d2 = new OrderDetail(200); public Order() { OrderDetail d3 = new OrderDetail(300); } OrderDetail d4 = new OrderDetail(400); public static void main(String[] args) { new Order(); } } class OrderDetail { public OrderDetail(Integer price) { System.out.println("OrderDetail price=" + price); } }
執行結果:
OrderDetail price=100 OrderDetail price=200 OrderDetail price=400 OrderDetail price=300