Java_从入门到JavaEE_12+13

一、内部类

  1. 理解:一个类中再声明另外一个类
  2. 分类:
    1. 成员内部类
    2. 静态内部类
    3. 接口内部类
    4. 局部内部类
    5. 匿名内部类

1.成员内部类

案例:创建成员内部类的对象,并调用方法

java 复制代码
import com.lv.outter_inner_02.Outter.Inner;
public class Test {
	public static void main(String[] args) {
		Inner inner = new Outter().new Inner();
		inner.method();
	}
}
package com.lv.outter_inner_02;
//外部类
public class Outter {
	private 	String str1 = "属性1";
				String str2 = "属性2";
	protected 	String str3 = "属性3";
	public 		String str4 = "属性4";
	final 		String str5 = "属性5";
	static 		String str6 = "属性6";
	static final String str7 = "属性7";

	//成员内部类
	class Inner{
		String str1 = "成员内部类的属性";
		public void method(){
			System.out.println("成员内部类的方法");
			System.out.println(str1);//this.str1
			System.out.println(Outter.this.str1);
			System.out.println(str2);//Outter.this.str2
			System.out.println(str3);//Outter.this.str3
			System.out.println(str4);//Outter.this.str4
			System.out.println(str5);//Outter.this.str5
			System.out.println(str6);//Outter.str6
			System.out.println(str7);//Outter.str7
		}
	}	
}

总结:

  1. 创建成员内部类对象,必须先创建外部类对象,再创建内部类对象
  2. 成员内部类可以使用外部类所有的属性

2.静态内部类

案例:创建静态内部类的对象,并调用方法

java 复制代码
import com.lv.outter_inner_03.Outter.Inner;
public class Test {
	public static void main(String[] args) {
		Inner inner = new Outter.Inner();
		inner.method();	
	}
}
package com.lv.outter_inner_03;
//外部类
public class Outter {	
	static 		String str1 = "属性1";
	static final String str2 = "属性2";
	//静态内部类
	static class Inner{		
		public void method(){
			System.out.println("静态内部类的方法");
			System.out.println(str1);//Outter.str6
			System.out.println(str2);//Outter.str7
		}
	}
	
}

总结:

  1. 创建静态内部类对象,不用创建外部类对象
  2. 静态内部类只能使用外部类的静态属性

3.接口内部类

案例:创建接口内部类的对象,并调用方法

java 复制代码
import com.lv.outter_inner_04.Outter.Inner;
public class Test {
	public static void main(String[] args) {	
		Inner inner = new Outter.Inner();
		inner.method();	
	}
}
package com.lv.outter_inner_04;
//外部接口
public interface Outter {	
	//接口内部类
	//public static class Inner{
	class Inner{
		public void method(){
			System.out.println("接口内部类的方法");
		}
	}	
}

总结:

  1. 接口内部类就是静态内部类
  2. 接口内部类默认使用public static修饰

4.局部内部类

案例:调用局部内部类里的方法

java 复制代码
package com.lv.outter_inner_05;
public class Test {
	public static void main(String[] args) {
		Outter outter = new Outter();
		outter.method();
	}
}
package com.lv.outter_inner_05;
//外部类
public class Outter {
	public void method(){		
		//局部内部类
		class Inner{
			public void innerMethod(){
				System.out.println("局部内部类里的方法");
			}
		}		
		//创建局部内部类对象
		Inner inner = new Inner();
		inner.innerMethod();
	}
}

总结:

  1. 局部内部类不能使用访问修饰符修饰(因为局部内部类的作用域就是在该方法内)
  2. 局部内部类使用到外部类方法里的变量,该变量在JDK1.8开始会自动变成常量

5.匿名内部类

案例:

java 复制代码
package com.lv.outter_inner_08;
public class Test {
	public static void main(String[] args) {	
		A a = new A() {		
			@Override
			public void method() {
				// TODO Auto-generated method stub				
			}
		};	
		a.method();
	}
}
package com.lv.outter_inner_08;
public abstract class A {
	public abstract void method();
}

实现过程:

  1. 底层创建匿名类(Test01$1.class),继承A类,重写method()
  2. 创建匿名类对象
  3. 将匿名类对象的内存地址赋值给父类的引用 -- 多态

6.应用场景

  1. A类的对象只在B类中使用,并且A类使用到B类所有的属性 -- 可以将A类设置为B类的成员内部类(常用)
  2. A类的对象只在B类中使用,并且A类使用到B类的静态属性 -- 可以将A类设置为B类的静态内部类(常用)
  3. A类(抽象类)的子类只创建一次对象,就没必要去创建子类 -- 直接使用匿名内部类(new A())(常用)
  4. I1接口的实现类只创建一次对象,就没必要去创建实现类 -- 直接使用匿名内部类(new I1())(常用)
  5. A类的对象只在B类某个方法中使用 -- 可以将A类设置为B类的局部内部类(少见)
  6. A类的对象只在I1接口中使用 -- 可以将A类设置为I1接口的接口内部类(少见)

二、常用类

1.包装类/封装类

  1. 理解:包装类是8种基本数据类型对应的类

  2. 出现原因:

    ​ Java为纯面向对象语言(万物皆对象),但是8种基本数据类型不能new对象,破坏了Java为纯面向对象语言的特征,所以Java又为8种基本你数据类型分别匹配了对应的类,这种类叫做包装类/封装类

  3. 基本数据类型与引用数据类型继承关系

    基本数据类型 引用数据类型 继承关系
    byte Byte Object.Number.Byte
    short Short Object.Number.Short
    int Integer Object.Number.Integer
    long Long Object.Number.Long
    float Float Object.Number.Float
    double Double Object.Number.Double
    char Character Object.Character
    boolean Boolean Object.Boolean

    注意:int类型对应的包装类是Integer,char类型对应的包装类是Character

  4. 以int为例:

    java 复制代码
    package com.lv.package_class;
    
    public class Test {
    public static void main(String[] args) {		
    		//手动装箱:基本数据类型 转 引用数据类型
    		int a = 100;
    		Integer integer = Integer.valueOf(a);
    		System.out.println(integer);		
    		//手动拆箱:引用数据类型 转 基本数据类型
    		Integer integer = new Integer(100);
    		int b = integer.intValue();
    		System.out.println(b);		
    		
        //JDK1.5开始提供自动装箱和自动拆箱的特性		
    		//自动装箱:基本数据类型 转 引用数据类型
    		int c = 100;
    		Integer integer = c;//底层实现:Integer.valueOf(i);
    		System.out.println(integer);		
    		//自动拆箱:引用数据类型 转 基本数据类型
    		Integer integer = new Integer(100);
    		int d = integer;//底层实现:integer.intValue();
    		System.out.println(d);
    		
    		//将字符串转换为int
    		String str = "123";
    		int e = Integer.parseInt(str);
    		System.out.println(e);
    	}
    }

    经验:学习包装类要举一反三

  5. 包装类(int为例)深入

    java 复制代码
    package com.lv.package_class;
    
    public class Test {
    	public static void main(String[] args) {
    		
    		Integer integer1 = Integer.valueOf(100);
    		Integer integer2 = Integer.valueOf(100);
    		System.out.println(integer1 == integer2);//true
    		
    		Integer integer3 = Integer.valueOf(200);
    		Integer integer4 = Integer.valueOf(200);
    		System.out.println(integer3 == integer4);//false
    		
    	}
    }

    底层分析:

    在Integer中,有一个Integer的缓存类

    java 复制代码
    public static Integer valueOf(int i){
    		
    		if(i>=IntegerCache.low && i<=IntegerCache.higt){
    			return IntegerCache.cache[i-IntegerCache.low];
    		}
    		return new Integer(i);
    	}
    private static class IntegerCache{	
    		static final int low = -128;
    		static final int higt = 127;
    		static final Integer[] cache;
    		
    		static{
    			cache = new Integer[higt - low + 1];
    			
    			int j = low;
    			for (int i = 0; i < cache.length; i++) {
    				cache[i] = new Integer(j++);
    			}
    		}	
    	}

    当输入值超出范围时就会return新的Integer对象,

    这就是为什么System.out.println(integer3 == integer4);的结果为false。

2.字符串的类

  1. 分类:
    1. String
    2. StringBuffer
    3. StringBuilder
1.String的使用
  1. 案例以及分析:
java 复制代码
package com.lv.string_class;

public class Test {
	public static void main(String[] args) {
		String str = "123abc";
		
		str = str.concat("DEF123");//concat在末尾追加,并返回新的字符串
		str = str.substring(2);//substring从开始下标处截取到字符串末尾,并返回新的字符串
		str = str.substring(1, 7);//substring从开始下标处(包含)截取到结束下标处(排他),并返回新的字符串
		
		str = str.toLowerCase();//toLowerCase转小写,并返回新的字符串
		str = str.toUpperCase();//toUpperCase()转大写,并返回新的字符串

		//--------------------------------------------------------------------
		
		str = "   123   abc   DEF   123         ";
		
		str = str.trim();//trim去除首尾空格,并返回新的字符串
		str = str.replace('2', '6');//replace替换字符,并返回新的字符串
		str = str.replaceAll("163", "666888");//replaceAll替换字符串,并返回新的字符串
		str = str.replaceFirst("666", "7777");//replaceFirst替换第一次出现的字符串,并返回新的字符串
		str = str.replaceAll(" ", "");//去除空格(将空格字符串替换成空内容的字符串)
		
		System.out.println("判断两个字符串是否相同(区分大小写):" + str.equals("7777888abcDEF666888"));
		System.out.println("判断两个字符串是否相同(不区分大小写):" + str.equalsIgnoreCase("7777888ABCDEF666888"));
		
		System.out.println("判断字符串是否以某个字符串开头:" + str.startsWith("777"));
		System.out.println("判断字符串是否以某个字符串结尾:" + str.endsWith("666888"));
		
		System.out.println("查询出子字符串在字符串中第一次出现的下标:" + str.indexOf("88"));
		System.out.println("查询出子字符串在字符串中最后一次出现的下标:" + str.lastIndexOf("88"));
		
		System.out.println("获取指定下标上的字符:" + str.charAt(7));
		
		System.out.println(str);//7777888abcDEF666888
		
		//-------------------------------------------------------------
		
		//将其他类型转型成String
		System.out.println(String.valueOf(100));//int -> String
		System.out.println(String.valueOf(123.123));//double -> String
		System.out.println(String.valueOf('a'));//char -> String
		System.out.println(String.valueOf(true));//boolean -> String
		System.out.println(String.valueOf(new char[]{'a','b','c'}));//char[] -> String
		
		//将其他类型转型成String -- 简化版
		System.out.println(100 + "");
		System.out.println(123.123 + "");
		System.out.println('a' + "");
		System.out.println(true + "");
		
	}
}
  1. 深入------String拼接创建对象

    案例以及分析:

    java 复制代码
    package com.lv.string_class;
    
    public class Test {
    	public static void main(String[] args) {		
    		String str1 = "abc";
    		String str2 = "abc";
    		System.out.println(str1 == str2);//true		
    		//两个常量在编译时直接拼接
    		String str3 = "ab" + "c";
    		System.out.println(str1 == str3);//true		
    		//两个常量在编译时直接拼接
    		final String s1 = "ab";
    		final String s2 = "c";
    		String str4 = s1 + s2;//反编译:String str4 = "abc";
    		System.out.println(str1 == str4);//true		
    		//变量拼接,底层会创建StringBuilder对象
    		String s3 = "ab";
    		String s4 = "c";
    		String str5 = s3 + s4;//底层实现:String str5 = (new StringBuilder(String.valueOf(s3))).append(s4).toString()
    		System.out.println(str1 == str5);//false	
    	}
    }
2.StringBuffer的使用
  1. 案例以及分析:

    java 复制代码
    package com.lv.string_class;
    public class Test02 {
    	public static void main(String[] args) {		
    		//创建StringBuffer对象
    		StringBuffer sb = new StringBuffer();		
    		//在末尾追加字符串
    		sb.append("123abc");
    		sb.append("DEF123");		
    		sb.insert(6, "XXYYZZ");//将字符串插入到指定下标的位置
    		sb.setCharAt(6, 'x');//替换指定下标上的字符
    		sb.replace(3, 6, "aabbcc");//替换开始下标处(包含)到结束下标处(排他)的字符串
    		sb.deleteCharAt(3);//删除指定下标上的字符
    		sb.delete(3, 17);//删除开始下标处(包含)到结束下标处(排他)的字符串
    		sb.reverse();//反转字符串		
    		System.out.println(sb.toString());//321321
    	}
    }
  2. StringBuffer的深入 -- StringBuffer底层源码

    见StringBuffer底层源码分析

3.StringBuilder的使用

理解

  1. StringBuilder代表可变的字符序列。
  2. StringBuilder称为字符串缓冲区

工作原理:

  1. 预先申请一块内存,存放字符序列,如果字符序列满了,会重新改变缓存区的大小,以容纳更多的字符序列。
    StringBuilder是可变对象,这个是String最大的不同

深入:现在的需求要存储10000个长度的数据,不要使用new StringBuilder()的方式,因为使用无参构造,底层会创建16长度的容器,存储10000个数据需要多次扩容,效率极低,直接使用new StringBuilder(10000)的方式,一步到位。

4.StringBuffer和StringBuilder区别
  1. StringBuffer和StringBuilder在使用层面上是一模一样的(调用方法)
  2. StringBuffer和StringBuilder都是继承的同一个父类(AbstractStringBuilder),而且底层实现都是依赖于父类
  3. 唯一不同就是StringBuffer方法上加了锁(synchronized),就意味着StringBuffer是线程安全的

应用场景:

  1. 单线程的程序:使用StringBuilder,因为不上锁
  2. 多线程的程序:使用StringBuffer,上锁是因为不让其他线程抢到资源

注意:StringBuilder的效率比StringBuffer高,因为没有上锁和解锁的过程

5.频繁的拼接字符串使用StringBuilder或StringBuffer

当频繁使用拼接字符串时:

String的底层实现:

str = str + "11223";

str = new StringBuidler(String.valueOf(str)).append("11223").toString();

这样会导致内存占用过高。

相关推荐
P.H. Infinity11 分钟前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天15 分钟前
java的threadlocal为何内存泄漏
java
caridle26 分钟前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
萧鼎29 分钟前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸30 分钟前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农30 分钟前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^31 分钟前
数据库连接池的创建
java·开发语言·数据库
苹果醋335 分钟前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花40 分钟前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端42 分钟前
第六章 7.0 LinkList
java·开发语言·网络