当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上 的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象, 其方法才可以供外部调用。
我们有时候希望无论是否产生了对象或无论产生了多少 对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个 国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中 都单独分配一个用于代表国家名称的变量。
使用static修饰属性:静态变量
使用范围:
在Java类中,可用static修饰属性、方法、代码块、内部类
被修饰后的成员具备以下特点:
随着类的加载而加载
优先于对象存在
修饰的成员,被所有对象所共享
访问权限允许时,可不创建对象,直接被类调用
类中的常量也常常声明为static
由于类只会加载一次,则静态变量在内存也只会存在一份,存放在方法区的静态域中。
属性的分类:按是否使用static修饰,又分为:静态属性和非静态属性(实例变量)。
实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性,当修改其中一个对象的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享一个静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过的

如果想让一个类的所有实例共享数据,就用类变量!
静态结构使用例:
System.out 、Math.PI
使用static修饰方法:静态方法
随着类的加载二加载,可以通过类.静态方法的方式进行调用
静态方法中只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
静态方法中不能使用this和super关键字
类属性作为该类各个对象之间共享的变量。在设计类时,分析哪 些属性不因对象的不同而改变,将这些属性设置为类属性。相应的方法设置为类方法。
如果方法与调用者无关,则这样的方法通常被声明为类方法,由于不需要创建对象就可以调用类方法,从而简化了方法的调用。
操作静态属性的方法通常设置为静态
工具类的方法习惯上声明为static
- package com.xxx.java;
-
- public class StaticTest {
- public static void main(String[] args) {
-
- Chinese c1 = new Chinese();
- c1.name = "姚明";
- c1.age = 40;
-
- Chinese c2 = new Chinese();
- c2.name = "马龙";
- c2.age = 30;
-
- c1.nation = "CHN";
- System.out.println(c2.nation);
-
- Chinese.show();
- //Chinese.eat();
- }
- }
-
- class Chinese{
-
- String name;
- int age;
- static String nation;
-
- public void eat() {
- System.out.println("吃中餐");
- }
-
- public static void show() {
- System.out.println("我是一个中国人");
- //eat();
- //name = "Tom";
- //可以调用静态的结构
- nation = "中国";
- walk();
- }
-
- public static void walk() {
- System.out.println("走路");
- }
- }
- package com.xxx.java;
-
- //自定义数组工具类
-
- public class ArrayUtil {
- // 求数组的最大值
- public static int getMax(int[] arr) {
- int max = arr[0];
- for (int i = 0; i < arr.length; i++) {
- if (max < arr[i]) {
- max = arr[i];
- }
- }
- return max;
- }
-
- // 求数组的最小值
- public static int getMin(int[] arr) {
- int min = arr[0];
- for (int i = 0; i < arr.length; i++) {
- if (min > arr[i]) {
- min = arr[i];
- }
- }
- return min;
- }
-
- // 求数组的总和
- public static int getSum(int[] arr) {
- int sum = 0;
- for (int i = 0; i < arr.length; i++) {
- sum += arr[i];
- }
- return sum;
- }
-
- // 求数组的平均值
- public static int getAvg(int[] arr) {
- return getSum(arr) / arr.length;
- }
-
- // 反转数组
- public static void reverse(int[] arr) {
- for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
- int temp = arr[i];
- arr[i] = arr[j];
- arr[j] = temp;
- }
- }
-
- // 复制数组
- public static int[] copy(int[] arr) {
- int[] arr1 = new int[arr.length];
- for (int i = 0; i < arr.length; i++) {
- arr1[i] = arr[i];
- }
- return arr1;
- }
-
- // 数组排序
- public static void sort(int[] arr) {
- for (int i = 0; i < arr.length; i++) {
- for (int j = 0; j < arr.length - 1 - i; j++) {
- if (arr[j] > arr[j + 1]) {
- swap(arr,j,j+1);
- }
- }
- }
- }
-
- // 遍历数组
- public static void print(int[] arr) {
- for (int i = 0; i < arr.length; i++) {
- System.out.print(arr[i] + " ");
- }
- }
-
- // 查找指定元素
- public static int getIndex(int[] arr, int dest) {
-
- for (int i = 0; i < arr.length; i++) {
- if (dest == arr[i]) {
- return i;
- }
- }
- return -1;
- }
- //交换数组中指定两个位置元素的值
- private static void swap(int[]arr,int i,int j) {
- int temp = arr[i];
- arr[i] = arr[j];
- arr[j] = temp;
- }
- }
测试
- package com.xxx.java;
-
- public class ArrayUtilTest {
- public static void main(String[] args) {
- //ArrayUtil util = new ArrayUtil();
- int[] arr = {32,34,32,5,3,54,654,-98,0,-53,5};
-
- int max = ArrayUtil.getMax(arr);
- System.out.println("最大值为:" + max);
-
- // System.out.println("排序前");
- // ArrayUtil.print(arr);
- //
- // ArrayUtil.sort(arr);
- // System.out.println();
- // System.out.println("排序后");
- // ArrayUtil.print(arr);
-
- System.out.print("查找:");
- int index = ArrayUtil.getIndex(arr, -5);
- if (index >= 0) {
- System.out.println(index);
- } else {
- System.out.println("没找到");
- }
- }
- }
- package com.xxx.java;
-
- public class CircleTest {
- public static void main(String[] args) {
- Circle c1 = new Circle();
- Circle c2 = new Circle();
- Circle c3 = new Circle(3.4);
-
- System.out.println("c1的id为:" + c1.getId());
- System.out.println("c2的id为:" + c2.getId());
- System.out.println("c3的id为:" + c3.getId());
-
- System.out.println("创建的圆的个数为:" + Circle.getTotal());
- }
- }
-
- class Circle {
- private double radius;
- private int id;
-
- private static int total;
- private static int init = 1001;
-
-
-
- public Circle() {
- super();
- id = init++;
- total++;
- }
-
-
-
- public Circle(double radius) {
- this();
- this.radius = radius;
- //id = init++;
- //total++;
- }
-
-
-
- public static int getTotal() {
- return total;
- }
-
-
-
- public double getRadius() {
- return radius;
- }
-
-
-
- public void setRadius(double radius) {
- this.radius = radius;
- }
-
-
-
- public int getId() {
- return id;
- }
-
-
-
- public double findArea() {
- return 3.14 * radius * radius;
- }
- }
编写一个类实现银行账户的概念,包含的属性有“帐号”、“密 码”、“存款余额”、“利率”、“最小余额”,定义封装这些 属性的方法。账号要自动生成。
编写主类,使用银行账户类,输入、输出3个储户的上述信息。 考虑:哪些属性可以设计成static属性。
- package com.xxx.exer;
-
- public class Account {
- private int id;
- private String pwd = "000000";
- private double balance;
-
- private static double interestRate;
- private static double minMoney;
- private static int init;
-
-
-
- public Account() {
- super();
- id = init++;
- }
-
-
- public Account(String pwd, double balance) {
- this();
- this.pwd = pwd;
- this.balance = balance;
- }
-
-
- public String getPwd() {
- return pwd;
- }
-
- public void setPwd(String pwd) {
- this.pwd = pwd;
- }
-
- public static double getInterestRate() {
- return interestRate;
- }
-
- public static void setInterestRate(double interestRate) {
- Account.interestRate = interestRate;
- }
-
- public static double getMinMoney() {
- return minMoney;
- }
-
- public static void setMinMoney(double minMoney) {
- Account.minMoney = minMoney;
- }
-
- public int getId() {
- return id;
- }
-
- public double getBalance() {
- return balance;
- }
-
-
- @Override
- public String toString() {
- return "Account [id=" + id + ", pwd=" + pwd + ", balance=" + balance + "]";
- }
-
- }
测试
- package com.xxx.exer;
-
- public class AccountTest {
- public static void main(String[] args) {
- Account.setInterestRate(0.012);
- Account.setMinMoney(100);
-
- Account acc1 = new Account();
- Account acc2 = new Account("114514",2000);
-
- System.out.println(acc1);
- System.out.println(acc2);
- System.out.println(Account.getInterestRate());
- System.out.println(Account.getMinMoney());
- }
- }
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、 以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。就像是经典的棋谱,不同的棋局,我们用不同的棋谱。”套路”
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对 某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构 造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生 类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无 法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象, 静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象 的变量也必须定义成静态的。
- package com.xxx.java1;
-
- public class SingletonTest1 {
- public static void main(String[] args) {
- Bank bank1 = Bank.getInstance();
- Bank bank2 = Bank.getInstance();
-
- System.out.println(bank1 = bank2);
- }
-
- }
- //饿汉式
- class Bank{
- //私有化构造器
- private Bank(){
-
- }
- //内部创建类的对象
- //要求声明为静态,否则静态方法中无法调用
- private static Bank instance = new Bank();
-
- //提供public的方法,返回类的对象
- public static Bank getInstance() {
- return instance;
- }
- }
懒汉式:
- package com.xxx.java1;
-
- public class SingletonTest2 {
- public static void main(String[] args) {
- Order order1 = Order.getInstance();
- Order order2 = Order.getInstance();
-
- System.out.println(order1 == order2);
- }
- }
- //懒汉式
- class Order {
- //私有化类的构造器
- private Order() {
-
- }
- //声明当前类对象,不进行初始化
- private static Order instance = null;
-
- //声明public static的返回当前类对象的方法
- public static Order getInstance() {
- //不判断会每次执行时都新生成一个对象实例
- if(instance == null) {
- instance = new Order();
- }
- return instance;
- }
- }
区分饿汉式和懒汉式:
懒汉式:
优点:延迟对象的创建
缺点:线程不安全——到多线程时修改
饿汉式:
优点:饿汉式是线程安全的
缺点:对象加载时间过长
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的 产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
网站的计数器,一般也是单例模式实现,否则难以同步。
应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
Application 也是单例的典型应用
Windows的Task Manager (任务管理器)就是很典型的单例模式
Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
说明
作为程序的入口
是一个普通的静态方法
public:由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public
static:又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static的
void:main方法执行完后程序就结束了,不需要返回值
形参:该方法接收一个String类型的数组参数,该数组中保存执行Java命令时传递给所运行 的类的参数。
1.先run as一遍代码
2.选择Run Configurations

3.左侧选择当前编译好的字节码文件,右侧选择Arguments

在Program arguments框内输入字符串,空格隔开,可以不加双引号。Run运行程序

执行结果如下

相关代码
- package com.xxx.java1;
-
- public class MainDemo {
- public static void main(String[] args) {
- for (int i = 0; i < args.length; i++) {
- System.out.println("***********" + args[i]);
- }
- }
- }
若是其他基本数据类型,可以使用包装类的parseXxx方法
- package com.xxx.java1;
-
- public class MainTest {
- public static void main(String[] args) {
- Main.main(new String[100]);
- }
- }
-
- class Main{
- public static void main(String[] args) {
- args = new String[100];
- for (int i = 0; i < args.length; i++) {
- args[i] = "args_" + i;
- System.out.println(args[i]);
- }
- }
- }
1、先删掉包名,在编译javac xxx
2、java xxx 形参
代码块(或初始化块)的作用:对Java类或对象进行初始化。
代码块(或初始化块)的分类:
一个类中代码块若有修饰符,则只能被static修饰,称为静态代码块 (static block),没有使用static修饰的,为非静态代码块。
static代码块通常用于初始化static的属性
静态代码块:
可以有输出语句。
初始化类的信息。
不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
若有多个静态的代码块,那么按照从上到下的顺序依次执行。
静态代码块的执行要先于非静态代码块。
静态代码块随着类的加载而加载,且只执行一次。
非静态代码块:
可以有输出语句。
可以在创建对象时,对对象的属性进行初始化。
除了调用非静态的结构外,还可以调用静态的变量或方法。
若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
每次创建对象的时候,都会执行一次。且先于构造器执行。
- package com.xxx.java2;
-
- public class BlockTest {
- public static void main(String[] args) {
- String desc = Person.desc;
- System.out.println(desc);
- Person p1 = new Person();
- Person p2 = new Person();
- System.out.println(p1.age);
- Person.info();
- }
- }
-
- class Person {
- //属性
- String name;
- int age;
- static String desc = "我是一个人";
-
- //构造器
- public Person() {
-
- }
-
- public Person(String name,int age) {
- this.name = name;
- this.age = age;
- }
-
- //代码块
- static {
- System.out.println("hello,static block-1");
- desc = "我是一个爱学习的人";
- info();
- }
- static {
- System.out.println("hello,static block-2");
- }
-
- {
- System.out.println("hello,block-1");
- age = 1;
- }
- {
- System.out.println("hello,block-2");
- }
- //方法
- public void eat() {
- System.out.println("吃饭");
- }
-
- @Override
- public String toString() {
- return "Person [name=" + name + ", age=" + age + "]";
- }
-
- public static void info() {
- System.out.println("我是一个快乐的人");
- }
- }
例1
- package com.xxx.java2;
- class Root{
- static{
- System.out.println("Root的静态初始化块");
- }
- {
- System.out.println("Root的普通初始化块");
- }
- public Root(){
- System.out.println("Root的无参数的构造器");
- }
- }
- class Mid extends Root{
- static{
- System.out.println("Mid的静态初始化块");
- }
- {
- System.out.println("Mid的普通初始化块");
- }
- public Mid(){
- System.out.println("Mid的无参数的构造器");
- }
- public Mid(String msg){
- //通过this调用同一类中重载的构造器
- this();
- System.out.println("Mid的带参数构造器,其参数值:"
- + msg);
- }
- }
- class Leaf extends Mid{
- static{
- System.out.println("Leaf的静态初始化块");
- }
- {
- System.out.println("Leaf的普通初始化块");
- }
- public Leaf(){
- //通过super调用父类中有一个字符串参数的构造器
- super("尚硅谷");
- System.out.println("Leaf的构造器");
- }
- }
- public class LeafTest{
- public static void main(String[] args){
- new Leaf();
- //new Leaf();
- }
- }
-
解析:
先加载父类和间接父类,然后加载每个类静态代码块即:
加载Object的静态代码块(无)
加载Root的静态代码块
加载Mid的静态代码块
加载Leaf的静态代码块
之后对象创建完毕,先加载父类和间接父类的构造器,而此时非静态代码块先于父类构造器执行:
加载Object的代码块(无),加载Object的构造器(无内容)
加载Root的代码块,加载Root的构造器
加载Mid的代码块,加载Mid的无参构造器,加载Mid的带参构造器
加载Leaf的代码块,加载Leaf的构造器
若再次new Leaf(),静态代码块内容不在执行
例2
- package com.xxx.java2;
-
- class Father {
- static {
- System.out.println("11111111111");
- }
- {
- System.out.println("22222222222");
- }
-
- public Father() {
- System.out.println("33333333333");
- }
-
- }
-
- public class Son extends Father {
- static {
- System.out.println("44444444444");
- }
- {
- System.out.println("55555555555");
- }
- public Son() {
- System.out.println("66666666666");
- }
-
-
- public static void main(String[] args) { // 由父及子 静态先行
- System.out.println("77777777777");
- System.out.println("************************");
- new Son();
- //System.out.println("************************");
-
- //new Son();
- //System.out.println("************************");
- //new Father();
- }
-
- }
解析:
main方法是由当前main所在的类通过类.main调用的,所有先初始化当前类以及他的父类和间接父类
当前main方法在Son中,由Son.main()调用,要初始化Son就要先初始化Son的父类和间接父类
初始化Object
初始化Father(静态代码块)
初始化Son(静态代码块)
后续执行同例1
结果为:1 4 7 * 2 3 5 6 * 2 3 5 6 * 2 3
1.默认初始化
2.显式初始化 / 3在代码块中赋值
4构造器中初始化
5对象.属性或对象.方法的方式赋值
执行顺序1——2 / 3——4——5
- package com.xxx.java2;
-
- public class OrderTest {
- public static void main(String[] args) {
- Order o = new Order();
- System.out.println(o.orderId);
- }
- }
-
- class Order{
- // int orderId = 3;
- // {
- // orderId = 4;
- // }
- {
- orderId = 4;
- }
- int orderId = 3;
-
- }
native关键字声明调用底层c或c++的方法
在Java中声明类、变量和方法时,可使用关键字final来修饰。
final标记的类不能被继承。
内置的final类:String、System、StringBuffer
final标记的方法不能被子类重写。
内置的funal方法:Object的getClass()
final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只能被赋值一次。
final修饰属性,可以赋值的位置有
显式初始化、在代码块中赋值、在构造器中赋值
final修饰局部变量:为常量,无法修改
修饰形参:表示此形参是一个常量,只能在方法内使用该形参,不能对其进行修改
static final:修饰属性 全局常量
- package com.xxx.java2;
-
- public class FinalTest {
-
- // final int UP; 无法默认初始化赋值
- final int WIDTH = 10; // 可以显式初始化赋值
- // 可以在代码块内赋值
- final int LEFT;
-
- {
- LEFT = 1;
- }
- // 可以在构造器中赋值,但每个构造器中都必须赋值
- final int RIGHT;
-
- public FinalTest() {
- RIGHT = 2;
- }
-
- public FinalTest(int n) {
- RIGHT = n;
- }
- //不可以在方法中赋值
- // final int DOWN;
- //
- // public int setDOWN(int down) {
- // DOWN = down;
- // }
-
- // public void doWidth() {
- // WIDTH = 20;
- // }
-
- public void show() {
- final int NUM = 10; //常量
- //NUM += 1;
- }
- public void show(final int num) {
- //num = 5;
- System.out.println(num);
-
- }
- public static void main(String[] args) {
- FinalTest test = new FinalTest();
- //test.setDOWN(5);
- test.show(10);
- }
- }
-
- final class FinalA {
-
- }
-
- //class B extends FinalA{
- //
- //}
-
- //class C extends String{
- //
- //}
-
- class AA {
- public final void name() {
-
- }
- }
-
- class BB extends AA {
- // public void name() {
- //
- // }
- }
1
- public class Something {
- public int addOne(final int x) {
- return ++x; //不行
- // return x + 1; //可以,x本身没有变
- }
- }
2
- public class Something {
- public static void main(String[] args) {
- Other o = new Other();
- new Something().addOne(o);
- }
-
- public void addOne(final Other o) {
- // o = new Other(); //不行,地址变了
- o.i++; //可以,地址没有变
- }
- }
-
- class Other {
- public int i;
- }