java对象和类

null引用

如果需要返回一个可变对象的引用,首先应该对它进行克隆。对象克隆是指存放在另一个新位置上的对象副本。例如

class Employee
{
	public Date gethireDay()
	{
		return (Date)hireDay.clone();
	}

权限修饰符

在这里插入图片描述

final 实例字段

final 修饰符对于类型为基本类型或者不可变类的字段尤其有用。对于可变的类,使用final修饰符可能会造成混乱。例如,考虑以下字段:
private final StringBuilder evaluations;
evaluations=new StringBuilder();
final关键字表示存储在evaluations变量中的对象引用不会再指示另一个不同的StringBuilder对象。不过这个对象可以更改:

package chapter_4;

public class final_my {
    private final String name="1213";
    private final StringBuilder evalutions;
    final_my(StringBuilder stringBuilder)
    {
        evalutions=stringBuilder;
    }
    void giveGoldStar()
    {
        evalutions.append('1');
        evalutions=new StringBuilder("12");
    }
    public static void main(String[] args) {
        final_my finalMy=new final_my(new StringBuilder("123"));
        
    }
}

静态常量

 public static final double PI=3.14;

静态方法

静态方法不能访问id实例字段,因为它不能在对象上执行操作。但是,静态方法可以访问静态字段。例如

 public static double getPI()
    {
        return PI;
    }

建议使用类名而不是对象来调用静态方法。

工厂方法

类似LocalDate 和NumberFormat的类使用静态工厂方法来构造对象。NumberFormat类如下生成不同风格的格式化对象:

  NumberFormat currencyFormatter=NumberFormat.getCurrencyInstance();
        NumberFormat percentformatter=NumberFormat.getPercentInstance();

为什么不适用构造器完成这些操作呢?

  • 无法命名构造器。构造器的名字必须和类名相同。但是,这里希望有两个不同的名字,分别得到货币实例和百分比实例。
  • 使用构造器时,无法改变所构造对象的类型。

方法参数

java 程序设计语言对对象采用的不是按引用调用,实际上,对象引用时按值传递的。
java 对方法参数能做什么和不能做什么

  • 方法不能修改基本数据类型的参数
  • 方法可以改变对象参数的状态
  • 方法不能让一个对象参数引用另一个新的对象
public static void swap(String a,String b)
    {
        String temp=a;
        a=b;
        b=temp;
    }
    public static void main(String[] args) {
        String a="12354";
        String b="1234565";
        swap(a,b);
        System.out.println(a);
        System.out.println(b);
    }

对象构造

默认字段初始化

如果在构造器中没有显示地位字段设置初值,那么就会自动被赋值为默认值,数值为0,布尔值为false,对象引用为null.

显示字段初始化

可以在类定义中直接为任何字段赋值,初始值不一定是常量值。例如

package chapter_4;

public class obvious_var_initial {
    private static int nextId;
    private int id=assignId();
    private static int assignId()
    {
        int r=nextId;
        nextId++;
        return r;
    }
}

调用另一个构造器

例如

 obvious_var_initial(double s)
    {
        this("Employee #"+nextId,s);
        nextId++;
    }
    obvious_var_initial(String name,double s)
    {
        
    }

初始化块

package chapter_4;

import java.util.Random;

public class initial_area {
    private static int nextId;
    private int id;
    private String name;
    private double salary;
    static
    {
        var generator=new Random();
        nextId= generator.nextInt(1000);
    }
    {
        id=1;
    }
    {
        id=nextId;
        nextId++;
    }
    initial_area()
    {

    }
    int getid()
    {
        return id;
    }

    public static void main(String[] args) {
        initial_area initialArea=new initial_area();
        System.out.println(initialArea.id);
        initial_area two=new initial_area();
        System.out.println(two.id);
        System.out.println(initial_area.nextId);

    }
}

static{ }的代码块要比普通的初始化块先调用。
下面是调用构造器的具体处理步骤:

  • 如果构造器的第一行调用了另一个构造器,则基于所提供的参数执行第二个构造器。
  • 2.否则
  • a)所有数据字段初始化为其默认值
  • b)按照在类声明中出现的顺序,执行所有字段初始化方法和初始化块。
  • 3.执行构造器主体代码

为了保证包名的唯一性,要用一个因特网域名以逆序的形式作为包名,然后对于不同的工程使用不同的子包,例如考虑域名horstmann.com
得到包名com.horstmann然后可以追加一个工程名,com.horstmann.corejava再把Employee类放在这个包里,那么全完限定名就是com.horstmann.corejava.Employee。

类的导入

我们可以采用两种方式访问另一个包中的公共类
,第一种方式就是使用完全限定名;就是包名后面跟着类名。例如

java.time.LocalDate today=java.time.LocalDate.now();

第二种是用import例如:

import java.time.*;

还可以导入一个特定的包,例如:

import java.time.LocalDate;

只能使用星号(*)导入一个包,而不能使用import java.或者import java..*导入以java为前缀的所有包
如果两个都有同一个名字的类,就会发生错误。例如:

package chapter_4;
import java.util.*;
import java.sql.*;
public class import_class {
    public static void main(String[] args) {
        Date today;
    }
}

可以增加一个特定的import语句来解决这个问题。
例如

import java.util.Date;

如果两个Date类都要使用,可以在每个类名的前面加上完整的包名。

var deadline=new java.util.Date();
var today=new java.sql.Date(100);

在c++中,必须使用#include来加载外部特性的声明,这是因为,除了正在编译的文件以及在头文件中明确包含的文件,c++编译器无法查看任何其他文件的内部。java编译器则不同,可以查看其他文件的内部,只要告诉它到哪里去查看就可以了。在c++中与包机制类似的是命名空间,可以认为java中的package和import语句类似于c++中的namespace和using指令。

静态导入

有一种import 语句允许导入静态方法和静态字段,而不只是类。例如

import static java.lang.System.*;
public class import_class {
    public static void main(String[] args) {
        out.print("hello world");
    }
}

就可以使用System类的静态方法和静态字段,而不必加类名前缀。另外还可以导入特定的方法或字段;

import static java.lang.System.out;

在包中增加类

将源文件放到与完整包名匹配的子目录中。编译器将类文件也放在相同的目录结构中,需要注意,编译器处理文件(带有文件分隔符和扩展名.java的文件),而java解释器加载类。
编译器在编译源文件的时候不会检查目录结构,例如假定一个源文件开头有以下指令:

package com.mycompany;

即使这个源文件不在目录com/company下,也可以进行编译,吐过他不依赖于其他包,就可以通过编译而不出现编译错误,但是他无法运行,除非先将所有类文件移到正确的位置上。如果包与目录不匹配,虚拟机就找不到类。

在这里插入图片描述
为什么无法运行?

类路径

为了使类能被多个程序共享,需要做到以下几点:

  • 把类文件放到一个目录中,例如/home/user/classdir。需要注意的是,这个目录是包树状结构的基目录。如果希望增加com.horstmann.corejava.Employee类,那么Employee.class 类文件就必须位于子目录/home/user/classdir/com/horstmann/corejava中。
  • 2.将JAR文件(java归档)放在一个目录中,例如:/home/user/archives。
  • 3.设置类路径,类路径是所有包含类文件的路径的集合。
    在UNIX环境中,类路径的各项之间用冒号:分隔:
\home\user\classdir:.:\home\user\archives\archive.jar

而在windows环境中,都用句点(.)表示当前目录。
类路径包括:

  • 基目录/home/user/classdir或c:\classes;
  • 当前目录(.);
  • JAR文件/home/user/archives/archive.jar或c:\archives\archive.jar

从java6开始,可以在JAR文件目录中指定通配符,如下:
/home/user/classdir:.:/home/user/archives/‘*’
或者
c:\classdir;.;c:\archives*

类路径所列出的目录和归档文件是搜索类的起点。例如:
/home/user/classdir:.:/home/user/archives/archive.jar
假定虚拟机要搜寻com.horstmann.corejava.Employee类的类文件。它首先要查看java API类。显然,在那里找不到相应的类文件。所以转而查看类路径。然后查找以下文件:

  • /home/user/classdir/com/horstmann/corejava/Employee.class
  • com/horstmann/corejava/Employee.class(从当前目录开始)
  • com/horstmann/corejava/Employee.class(/home/user/archives/archive/jar中)

如果引用了一个类,而没有指定这个类的包,编译器将去查找这个类的包。它会查看所有import指令。例如:

import java.util.*;
import com.horstmann.corejava.*;

编译器会尝试查找java.lang.Employee(因为java.lang包总是会默认导入)、java.util.Employee,com.horstmann.corejava.Employee,如果找到了一个以上的类,就会报错,编译器还要查看源文件是否比类文件新,如果是就会再次自动重新编译。

设置类路径

不重要。

JAR文件

过了

类注解

类注解必须放在import语句之后,类定义之前。

方法注解

每一个方法注释必须放在描述的方法之前。除了通用标记之外,还可以使用下面的标记:

 public String name;
   /*
   * @return description
   * 
   * */
    void setName(String aname)
    {

    }

类设计技巧

1.一定要保证数据私有
2.一定要对数据进行初始化
3.不要在类中使用过多的基本类型。
4.不是所有的字段都需要单独的字段访问器和更改器。
5.分解有过多职责的类
6.类名和方法名要能够体现他们的职责。
7.优先使用不可变的类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值