1.内部类
什么是内部类:内部类就是在一个,类的内部在定义一个完整的类。
特点:
1.编译之后可以生成独立的字节码文件。
2.内部类可以直接访问外部类的私有成员,不破坏封装。
3.内部类可为外部类提供必要的内部功能组件。
内部类都有:
1.成员内部类
2.静态内部类
3.局部内部类
4.匿名内部类
1.1.成员内部类
成员内部类在类的内部定义,它是与实例变量,实例方法同级别的类。
package JavaClass;
public class Outer {
private int age = 20;
private String name = "张三";
// Inner就是Outer的成员内部类
class Inner{
private String address = "西安";
}
}
创建内部类对象时,必须依赖外部类对象。
package JavaClass;
import JavaClass.Outer.Inner;
public class TestClass {
public static void main(String[] args) {
// 外部类可以直接实例化
Outer out= new Outer();
// 内部类的实例化要借助外部类的实例化对象进行实例化,而且语法是外部类对象.new的形式
Inner in = out.new Inner();
// 调用内部类中的方法
in.fun();
}
}
当外部类,内部类存在重名属性时,会优先访问内部类属性,若想访问外部类属性,那么要在重名的属性前加上Outer.this
package JavaClass;
public class Outer {
private int age = 20;
private String name = "张三";
class Inner{
// 有相同的属性名
private String name = "李四";
public void fun(){
System.out.println(age);
// 打印的结果是李四
System.out.println(name);
// 打印的结果是张三
System.out.println(Outer.this.name);
}
}
}
注:成员内部类不能定义静态成员
1.2.静态内部类
将成员内部类设为static的,这样,内部类便不依赖外部类对象,可以直接创建或通过类名访问,也可以声明静态成员。
静态内部类和外部类的地位是相等的,在调用外部类的属性时,必须要先实例化。
public static void main(String[] args) {
// 静态内部类不依赖外部类
Inner in = new Inner();
in.fun();
// Outer.Inner inner = new Outer.Inner(); 这种方法也是可以的
}
1.3.局部内部类
定义在方法之中的类,叫局部内部类,范围仅限于当前的方法。
package JavaClass;
public class Outer {
// 外部类的属性
private int age = 20;
private String name = "张三";
// 方法
public void fun(){
// 局部内部类
// 前面不能加任何访问修饰符
class A{
private int num = 123;
public void fun2(){
System.out.println(age); // 可以访问
System.out.println(num);
}
}
}
}
调用局部内部类中的方法
public static void main(String[] args) {
Outer out = new Outer();
out.fun(); // 没有结果,因为没有用到类
}
实际上是没有任何输出信息的,因为在程序中,没有实例化局部内部类,更没有调用局部内部类中的方法。
只需要在fun方法的最后实例化局部内部类并且调用局部内部类中的方法就可以了
package JavaClass;
public class Outer {
private int age = 20;
private String name = "张三";
// 方法
public void fun(){
// 局部内部类
// 前面不能加任何访问修饰符
class Inner{
private int num = 123;
public void fun2(){
System.out.println(age); // 可以访问
System.out.println(num);
}
}
// --------------------------
Inner in = new Inner();
in.fun2();
// -------------------------
}
}
1.4.匿名内部类
没有类名的局部内部类,他必须继承一个父类或者实现一个接口。
引:实现接口的方法:定义实现类,定义局部内部类
接口:
package JavaClass;
public interface Usb {
void service();
}
实现类:
package JavaClass;
public class Mouse implements Usb{
@Override
public void service() {
System.out.println("Mouse实现了Usb");
}
}
main方法
package JavaClass;
public class TestClass {
public static void main(String[] args) {
// 定义一个实现类去实现了接口中的方法
Usb u1 = new Mouse();
u1.service();
class Fan implements Usb{
@Override
public void service() {
System.out.println("Fan实现了接口");
}
}
// 定义了一个局部内部类实现接口
Usb u2 = new Fan();
u2.service();
}
}
下面看匿名内部类是如何实现接口的(优化前两种方法)
package JavaClass;
public class TestClass {
public static void main(String[] args) {
Usb u = new Usb() {
// 实际上java内部创建了一个类只不过我们看不见
@Override
public void service() {
System.out.println("我用匿名内部类实现类接口");
}
}; // 注意这里是要有分号的
u.service();
// 但匿名内部类只能用一次
}
}
2.Object类
Object类是所有类的直接或间接父类,位于继承树的最顶层。任何类都默认继承Object类,否则为间接继承。Object类中的方法,是所有对象都具有的方法。
如果去看Object类的方法,会发现有很多方法都被native这个关键字修饰了,native表示该方法对应的实现在另外的文件中。
1.getClass方法,返回引用中存储的实际对象类型,通常用于判断两个对象是否是一个类型的类。
package JavaClass;
class A{
private String name;
public A(String s) {
this.name = s;
}
}
public class TestClass {
public static void main(String[] args) {
A a = new A("123");
A b = new A("456");
// 注意返回值类型是Class类型的
Class aa = a.getClass();
Class bb = b.getClass();
System.out.println(aa==bb);
}
}
2.hasCode方法,返回该对象hasCode值,一般情况下相同的对象有相同的hasCode值。
package JavaClass;
class A{
private String name;
public A(String s) {
this.name = s;
}
}
public class TestClass {
public static void main(String[] args) {
A a = new A("123");
A b = new A("456");
A c = a;
System.out.println(a.hashCode());// 460141958
System.out.println(b.hashCode());// 1163157884
System.out.println(c.hashCode());// 460141958
}
}
3.toStrong方法,返回该对象的字符串表达式,返回字符串类型。可以根据程序需求覆盖该方法。
注:直接输出对象其实就是输出该对象的toString方法。
4.equals方法,比较两个对象的地址是否相等。内部return(this == obj)。
3.包装类Integer
概述:包装类就是将基本数据类型包装成的一个类,除了保留了基本数据类型的值以外,还在包装类中添加了许多方法。
1.基本数据类型和包装类型之间的转换
package JavaClass;
public class TestClass {
public static void main(String[] args) {
// JDK1.5之后,自动打包机制
Integer aa = 1;
System.out.println(aa);
int a = new Integer(2);
System.out.println(a);
// 以前主要使用这两种方法进行类型之间的转换
// 1.intValue(),非静态方法,Integer--->int
// 2.valueOf(),静态方法,int--->Integer
int b = aa.intValue();
int c = 5;
Integer cc = Integer.valueOf(c);
}
}
2.基本类型和字符串之间的转换
package JavaClass;
public class TestClass {
public static void main(String[] args) {
int a = 1;
String s1 = a+"";
// 通过加号可以实现
int b = 2;
String s2 = Integer.toString(b);
// 通过toString方法实现基本类型转换成字符串类型
///
String s3 = "100";
int c = Integer.parseInt(s3);
// 通过parseInt可以将字符串类型转换为基本类型
}
}
注意:
在Boolean(包装类型)中,将字符串转换为基本数据类型时
“true” —-> true
非”true” —-> false
3.Integer缓冲区
package JavaClass;
public class TestClass {
public static void main(String[] args) {
Integer i1 = new Integer(100);
Integer i2 = new Integer(100);
System.out.println(i1 == i2);
// 这两个值不相等,因为i1和i2在堆内存中是两个不同的对象
System.out.println(i1.equals(i2));
// 相等,因为Integer内部重写了equals方法
Integer i3 = 100;
Integer i4 = 100;
System.out.println(i3 == i4);
// 输出true
Integer i5 = 200;
Integer i6 = 200;
System.out.println(i5 == i6);
// 输出false
// 为什么一个是100,一个是200,输出的结果会不一样
}
}
实际上,在内部进行自动包装时,Integer i3 = 100调用的是valudOf方法。底层会创建一个Integer数组,如果传进来的值为-128到127之间时,这些值会被放在Integer数组中,而Integer数组在堆内存中,所以使用 == 判断,两个值都为100的Integer对象实际上指向一个对象。如果值不在-128到127之间,那么就直接返回valueOf(n),此时两个值都为200的Integer对象指向两个对象。
java预先创建了256个常用的整数包装类对象,在实际开发当中,会对已经创建的这些对象进行复用。
4.String类
字符串是常量,创建之后不能改变。
字符串字面值会存储在字符串池中,可以共享。
字符串池在内存的方法区,不同于栈和堆。
String s = "zhangsan";
执行这句话时,系统会在栈和字符串池分别开辟一份空间,栈中的地址指向字符串池中的“zhangsan”。
s = "lisi";
此时,内存池会开辟一份空间存放“lisi”,而栈中的s会指向lisi,“zhangsan”如果在后面的程序中没有被使用,会变成垃圾变量。
String ss = "lisi";
此时,栈中的s和ss都指向字符串池中的lisi。
String sss = new String("wangwu");
此时会产生两个对象,堆和池中各存储一个对象,栈中的sss指向堆中的对象,堆中的对象会指向内存池中的“wangwu”。
所以说使用new的方式创建字符串会更占用资源。
package JavaClass;
public class TestClass {
public static void main(String[] args) {
String s = "a";
String ss = "a";
System.out.println(s == ss);
}
}
得到的结果是false,因为s和ss是指向池中的一块内存。
package JavaClass;
public class TestClass {
public static void main(String[] args) {
String s = new String("a");
String ss = new String("a");
System.out.println(s == ss); // 输出false,因为s和ss指向了堆中的两个不一样的内存
System.out.println(s.equals(ss)); // 输出true,因为String重写了equals方法。
}
}
5.可变字符串类
1.StringBuffer,可变长字符串,(相比StringBuilder)效率慢,线程安全。
2.Strinfbuilder,可变长字符串,(相比StringBuffer)效率快,线程不安全。
常用方法:
1.append(),追加。
2.insert(),插入。
3.replace(),替换。
6.Date类
Date类对象表示特定的时间,精确到毫秒,不过大多数方法已经被Calender类中的方法替代。
Date类重写了toString方法,用于打印时间,Calender中的toLocaleString方法也可以打印时间。
after方法和before方法,比较两个date对象谁在前谁在后,返回值为Boolean类型的。
compareTo方法,计算两个时间相差了多少毫秒。
// 格式化当前日期的方法
Date date=new Date();//获取当前的时间
SimpleDateFormat sd=new SimpleDateFormat("yyyy.MM.dd.HH.mm");//用这种格式去格式化
System.out.println(sd.format(date));
7.System类
System系统类,主要用于获取系统的属性数据和其他操作,构造方法是私有的。
我们可以通过currentTimemillis方法计算一段程序/一段代码的运行时间。