Java_从入门到JavaEE_12+13

一、内部类

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

1.成员内部类

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

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.静态内部类

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

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.接口内部类

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

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.局部内部类

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

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.匿名内部类

案例:

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. 基本数据类型与引用数据类型继承关系

    基本数据类型引用数据类型继承关系
    byteByteObject.Number.Byte
    shortShortObject.Number.Short
    intIntegerObject.Number.Integer
    longLongObject.Number.Long
    floatFloatObject.Number.Float
    doubleDoubleObject.Number.Double
    charCharacterObject.Character
    booleanBooleanObject.Boolean

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

  4. 以int为例:

    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为例)深入

    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的缓存类

    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. 案例以及分析:
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拼接创建对象

    案例以及分析:

    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. 案例以及分析:

    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();

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值