包
定义
包 (package) 是组织类的一种方式.
使用包的主要目的是保证类的唯一性.
概念图:
导入包中的类
Java 中已经提供了很多现成的类供我们使用
举例:
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date date = new Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
有一个万能的导包方式,一般都可以使用import java.util.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
Date date = new Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
但是有的时候会出现冲突,情况不多,这种是=时候要用完整的类名。
举例:
import java.util.*;
import java.sql.*;
public class Test {
public static void main(String[] args) {
// util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错
Date date = new Date();
System.out.println(date.getTime());
}
}
// 编译出错
Error:(5, 9) java: 对Date的引用不明确
java.sql 中的类 java.sql.Date 和 java.util 中的类 java.util.Date 都匹配
常见系统包
1.java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
2. java.lang.reflect:java 反射编程包;
3. java.net:进行网络编程开发包。
4. java.sql:进行数据库开发的支持包。
5. java.util:是java提供的工具程序包。(集合类等) 非常重要
6. java.io:I/O编程开发包。
静态导入
使用 import static 可以导入包中的静态的方法和字段。
举例:
import static java.lang.System.*;
public class Test {
public static void main(String[] args) {
out.println("hello");
}
}
使用这种方式可以更方便的写一些代码, 例如:
import static java.lang.Math.*;
public class Test {
public static void main(String[] args) {
double x = 30;
double y = 40;
// 静态导入的方式写起来更方便一些.
// double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
double result = sqrt(pow(x, 2) + pow(y, 2));
System.out.println(result);
}
}
包的访问权限
我们已经了解了类中的 public 和 private. private 中的成员只能被类的内部使用.
如果某个成员不包含 public 和 private 关键字, 此时这个成员可以在包内部的其他类使用, 但是不能在包外部的类使用.
举个例子:
Demo1和Demo2在一个包中,Test在另一个包中。
package com.bit.demo;
public class Demo1 {
int value = 0; }
package com.bit.demo;
public class Demo2 {
public static void Main(String[] args) {
Demo1 demo = new Demo1();
System.out.println(demo.value);
}
}
// 执行结果, 能够访问到 value 变量
10
import com.bit.demo.Demo1;
public class Test {
public static void main(String[] args) {
Demo1 demo = new Demo1();
System.out.println(demo.value);
}
}
// 编译出错
Error:(6, 32) java: value在com.bit.demo.Demo1中不是公共的; 无法从外部程序包中对其进行访
问
protected 关键字
如果把字段设为 private, 子类不能访问. 但是设成 public, 又违背了我们 “封装” 的初衷.两全其美的办法就是 protected 关键字。
对于类的调用者来说, protected 修饰的字段和方法是不能访问的
对于类的 子类 和 同一个包的其他类 来说, protected 修饰的字段和方法是可以访问的
举例:
// Animal.java
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
// Bird.java
public class Bird extends Animal {
public Bird(String name) {
super(name);
}
public void fly() {
// 对于父类的 protected 字段, 子类可以正确访问
System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
}
}
// Test.java 和 Animal.java 不在同一个 包 之中了.
public class Test {
public static void main(String[] args) {
Animal animal = new Animal("小动物");
System.out.println(animal.name); // 此时编译出错, 无法访问 name
}
}
小结:
Java 中对于字段和方法共有四种访问权限
private: 类内部能访问, 类外部不能访问
默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
public : 类内部和类的调用者都能访问
代码块
定义
使用 {} 定义的一段代码.
根据代码块定义的位置以及关键字,又可分为以下四种:
普通代码块
构造块
静态块
同步代码块
普通代码块:定义在方法中的代码块
public class Main{
public static void main(String[] args) {
{ //直接使用{}定义,普通方法块
int x = 10 ;
System.out.println("x1 = " +x);
}
int x = 100 ;
System.out.println("x2 = " +x);
}
}
// 执行结果
x1 = 10
x2 = 100
构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。
class Person{
private String name;//实例成员变量
private int age;
private String sex;
public Person() {
System.out.println("I am Person init()!");
}
//实例代码块
{
this.name = "bit";
this.age = 12;
this.sex = "man";
System.out.println("I am instance init()!");
}
public void show(){
System.out.println("name: "+name+" age: "+age+" sex: "+sex);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.show();
}
}
// 运行结果
I am instance init()! I am Person init()!
name: bit age: 12 sex: man
注意:实例代码块优先于构造函数执行
静态代码块:使用static定义的代码块。一般用于初始化静态成员属性
class Person{
private String name;//实例成员变量
private int age;
private String sex;
private static int count = 0;//静态成员变量 由类共享数据 方法区
public Person(){
System.out.println("I am Person init()!");
}
//实例代码块
{
this.name = "bit";
this.age = 12;
this.sex = "man";
System.out.println("I am instance init()!");
}
//静态代码块
static {
count = 10;//只能访问静态数据成员
System.out.println("I am static init()!");
}
public void show(){
System.out.println("name: "+name+" age: "+age+" sex: "+sex);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();//静态代码块是否还会被执行?
}
}
注意:
静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行
内部类
在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:静态内部类、匿名内部类、成员内部类和局部内部类。
定义在class 类名{}花括号外部的,即使是在一个文件里,也不是内部类了。
比如这样:
public class A{
}
class B{
}
静态内部类
public class Test {
static class B{
}
}
和静态变量、静态方法类似,静态内部类也是和当前类(Test)绑定。使用时,也是通过Test类来调用,如:
public class Test {
static class B{
}
public static void main(String[] args) {
B b1 = new Test.B();
//在当前类Test中使用时,和静态变量,静态方法类似,也可以把Test.B()省略写为B()
B b2 = new B();
}
}
匿名内部类
匿名内部类的定义,是在一个方法或是代码块中定义的类,并且没有显示申明类的名称,比如这样:
public class Test {
public static void main(String[] args) {
//定义了一个匿名内部类
A a = new A(){
};
}
}
class A{
}
匿名内部类是使用的非常多的一种内部类,和A a = new A(); 这样的实例操作不同,后边还有一个大括
号,表示可以重写方法,其实是定义了另外一个类(没有显示的类名,所以叫匿名)。经常用在需要实例化某个对象,但需要重写方法时,比如new接口,抽象类就是使用匿名内部类较多的方式。
public class Test {
public static void main(String[] args) {
//定义了一个匿名内部类
X x = new X(){
@Override
public void callback() {
}
};
}
}
interface X{
void callback();
}
类和对象的内存布局
局部变量和方法栈帧
public class Main{
public static void swap(int a, int b){
int tmp = a;
a = b;
b = tmp;
System.out.printf("swap a=%d, b=%d%n", a, b);
}
public static void main(String[] args) {
int a = 1;
int b = 2;
swap(a, b);
System.out.printf("main a=%d, b=%d%n", a, b);
}
}
//输出结果为
//swap a=2, b=1 main a=1, b=2
内存布局:对应程序的执行
整体看,某个方法进入时就有自己的方法栈帧,传入参数都是局部变量,方法退出后,所有栈帧内保存的局部变量就销毁了。
类和类变量
public class Main{
private static int COUNT;
public static void add(){
COUNT++;
}
public static void main(String[] args) {
add();
System.out.println(A.COUNT);
}
}
class A{
static int COUNT; }
对于类和类变量来说,一定要加载到类以后才会加载到方法区,并会进行初始化赋值。比如这里没有执行到A.COUNT时,A类不会加载到方法区。
对象和成员变量
public class Main{
public static void main(String[] args) {
Person p = new Person();
p.name = "张三";
p.age = 18;
p.sex = "男";
}
}
class Person{
String name;
int age;
String sex = "女"; }
对象要在成员变量初始化赋值完成,构造方法调用执行初始化操作以后,才算创建完成。
对象存储在堆里边,成员变量存储在堆里边的对象中。如果是成员变量是引用类型,会指向引用的对
象。