一、内部类
内部类:一个类里声明另外一个类,内部类可声明成public或private
变量:成员变量、静态变量、局部变量
内部类:
成员内部类、静态内部类、接口内部类、局部内部类、匿名内部类
1、成员内部类
public class Outter {
String str1="字符串1";
//成员内部类
public class Inner{
String str1="内部类字符串";
public void print() {
System.out.println(str1);
System.out.println(Outter.this.str1);
}
}
}
//成员内部类
public class Test01 {
public static void main(String[] args) {
//创建成员内部类对象的语法
Inner in = new Outter().new Inner();
in.print();
}
}
输出
2、静态内部类
(1)为什么静态内部类不能调用外部类的非静态属性?
创建静态内部类的对象,不会创建外部类的对象,外部类的属性就不会存在与堆内存中,就没有办法调用到
(2)为什么静态内部类可以调用外部类的静态属性?
创建静态内部类对象时,先把外部类的字节码文件加载到方法区中,并扫描该文件中的静态属性,然后放入静态常量区
public class Outter {
String str1="外部属性1";
static String str2="外部静态属性";
public static class Inner{
String str3="内部属性";
public void print() {
System.out.println(str2);
System.out.println(str3);
}
}
}
//静态内部类
public class Test01 {
public static void main(String[] args) {
//创建静态内部类对象的语法
Inner in = new Outter.Inner();
in.print();
}
}
输出
3、接口内部类
public interface IInterface {
public class Inner{
public void method() {
System.out.println("接口内部类");
}
}
}
//接口内部类
public class Test01 {
public static void main(String[] args) {
Inner in = new IInterface.Inner();
in.method();
}
}
输出:接口内部类
4、局部内部类
只能在外部类里创建内部类的对象
局部内部类只能访问方法中的final类型的局部变量,因为final定义的局部变量相当于一个常量,它的生命周期超出方法运行的生命周期。
//局部内部类
public class Outter {
public void method() {
class Inner{
public void print() {
System.out.println("局部内部类");
}
}
Inner in = new Inner();
in.print();
}
}
public class Test01 {
public static void main(String[] args) {
Outter out = new Outter();
out.method();
}
}
5、匿名内部类
匿名内部类的外部类是抽象类。
之前介绍的内部类只是单一的类,并没有继承或者实现任何类或接口,实际上也是可以继承一个抽象类或实现一个接口。
匿名对象:没有明确声明的对象,只使用一次的对象,即没有任何一个具体的对象名称引用它。这种操作可以节约内存。
匿名内部类(匿名子类):创建了一个没有名字的类,继承了MyClass,重写了method方法。
多态:创建该匿名内部类的对象,赋值给父类的引用。
(1)匿名内部类
public abstract class MyClass {
public abstract void method();
}
public class Test01 {
public static void main(String[] args) {
MyClass m = new MyClass() {
@Override
public void method() {
System.out.println("匿名内部类");
}
};
m.method();
}
}
输出:匿名内部类
(2)接口类匿名内部类
public interface IInterface {
public void method();
}
public class Test02 {
public static void main(String[] args) {
IInterface I=new IInterface() {
@Override
public void method() {
System.out.println("接口匿名内部类");
}
};
I.method();
}
}
输出:接口匿名内部类
(3)匿名内部类的应用
public interface ICode {
public void runTime();
}
//计算for循环运行的时间
//匿名内部类创建的对象作为testCode方法的输入
public class Test01 {
public static void main(String[] args) {
long testcode = testCode(new ICode() {
@Override
public void runTime() {
String str="";
for(int i=0;i<10000;i++) {
str+="哈哈";
}
}
});
System.out.println(testcode);
}
public static long testCode(ICode c) {
long time1 = System.currentTimeMillis();
c.runTime();
long time2 = System.currentTimeMillis();
return time2-time1;
}
}
二、内存分析
栈: 调用方法就会开辟空间,并存储商法中的局部变量,方法一旦执行完毕,开辟的空间就会被立刻回收。
堆: 存储对象
方法区: 存储字节码文件,项目结束时被清空。
静态常量区: 存储static修饰的变量,项目结束时被清空。
常量区: 存储final及字面值常量,项目结束时被清空。
三、单例设计模式
单例设计模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要有三点:
(1)构造方法私有化
(2)声明一个本类对象
(3)给外部提供一个静态方法获取对象实例
在项目中为什么要使用单例,单例有什么好处?
1、在设计一些工具类的时候(通常工具类,只有功能方法,没有属性)
2、工具类可能会被频繁调用
目的是为了节省重复创建对象所带来的内存消耗,从而来提高效率。
能不能使用构造方法私有化+静态方法来替代单例?
两种实现方式:
1、饿汉式
在类被加载后,对象被创建,到程序结束后释放。
占用内存时间长,效率高,线程安全。立刻加载
public class Hungry {
private static Hungry m= new Hungry();
Hungry() {}
public static Hungry getInstance() {
return m;
}
public void method() {
System.out.println("饿汉式");
}
}
public class Test01 {
public static void main(String[] args) {
Hungry m1=Hungry.getInstance();
Hungry m2=Hungry.getInstance();
System.out.println(m1==m2);
}
}
结果:true
2、懒汉式
在第一次调用getInstance方法时,对象被创建,到程序结束后。
占用内存时间短,效率低,线程不安全(在多线程访问时会有安全问题)。延时加载
public class Lazy {
static Lazy m = null;
private Lazy() {}
public static Lazy getInstance() {
if(m == null) {
m = new Lazy();
}
return m;
}
public static void method() {
System.out.println("哈哈哈哈");
}
}
public class Test01 {
public static void main(String[] args) {
Lazy m1 = Lazy.getInstance();
Lazy m2 = Lazy.getInstance();
m1.method();
m2.method();
}
}
结果:
哈哈哈哈
哈哈哈哈
四、简单工厂设计模式
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式。
当使用者和被使用者两者之间耦合,产生依赖,当被使用者改变时,会影响使用者。可使用工厂模式来降低两者之间的依赖。
需求:娃娃工厂生产瓷娃娃和布娃娃。
// 娃娃抽象类
public abstract class Doll {
public abstract void use();
}
//瓷娃娃
public class CiDoll extends Doll{
@Override
public void use() {
System.out.println("瓷娃娃是摆设!");
}
}
//布娃娃
public class BuDoll extends Doll{
@Override
public void use() {
System.out.println("布娃娃是玩偶!");
}
}
使用单例设计模式(懒汉式)创建一个工厂
娃娃工厂类具有生产娃娃的方法
//娃娃工厂类
public class DollFactory {
public static final int CI_DOLL=1;
public static final int BU_DOLL=2;
//懒汉式
private static DollFactory factory = null;
private DollFactory() {}
public static DollFactory getInstance() {
if(factory == null) {
factory = new DollFactory();
}
return factory;
}
//生产娃娃
public Doll ProduceDoll(int type) {
Doll doll = null;
switch(type){
case CI_DOLL:
doll=new CiDoll();
break;
case BU_DOLL:
doll=new BuDoll();
break;
default:
break;
}
return doll;
}
}
public class Test01 {
public static void main(String[] args) {
DollFactory factory = DollFactory.getInstance();
Doll doll = factory.ProduceDoll(DollFactory.CI_DOLL);
doll.use();
Doll doll2 = factory.ProduceDoll(DollFactory.BU_DOLL);
doll2.use();
}
}
输出:
瓷娃娃是摆设!
布娃娃是玩偶!
五、基本数据类型包装类
基本数据类型不具有对象的特性,不能满足某些特殊的需求。从JDK中可以知道,Java中的很多类的很多方法的参数类型都是Object,即这些方法接收的参数都是对象,同时,又需要用这些方法来处理基本数据类型的数据,这时就要用到包装类。
基本数据类型 | 基本数据类型包装类 |
---|---|
int | Interger |
char | Character |
float | Float |
double | Double |
byte | Byte |
long | Long |
short | Short |
boolean | Boolean |
装箱:基本数据类型 --> 包装类
Integer integer = Integer.valueOf(10);
拆箱:包装类 --> 基本数据类型
int i = integer.intValue();
自动装箱 基本类型—引用类型:整型在特定情况下会自动转换为Integer类型。
自动拆箱 引用类型—基本类型:Integer类型在特点情况下会自动转换为整型。
Integer类:
paeseInt()方法:将一个字符串转换成基本数据类型;
valueOf(int i) : 返回一个表示指定的 int 值的 Integer 实例。
六、String类
public static void main(String[] args) {
//String类的常用方法
String str = "123abcDEF123";
str = str.concat("4567");在末尾追加字符串,并返回新的字符串
str = str.substring(2);从开始下标处截取到末尾,并返回新的字符串
str = str.substring(2, 9);从开始下标(包含)处截取到结束下标(不包含),并返回新的字符串
str = str.toLowerCase();转小写,并返回新的字符串
str = str.toUpperCase();转大写,并返回新的字符串
str = " 123 abcd EDF 123 ";
str = str.trim();去掉首尾空格,并返回新的字符串
str = str.replace(" ", "a");把空字符替换成 a字符串
// System.out.println(str);//123aabcdaEDFaaa123
System.out.println("该字符串的字符个数:" + str.length());
System.out.println("比较字符串内容是否相同:" + str.equals("123aabcdaEDFaaa123"));
System.out.println("比较字符串内容是否相同(不区分大小写):" + str.equalsIgnoreCase("123AAbcDaedFaaa123"));
System.out.println("判断是否以某个字符串开头:" + str.startsWith("123"));
System.out.println("判断是否以某个字符串结尾:" + str.endsWith("aaa123"));
int indexOf1 = str.indexOf(97);查询ASCII
int indexOf2 = str.indexOf("2");查询目标字符串在原字符串中的下标
System.out.println("获取下标上的单个字符:" + str.charAt(7));
将其他类型转换为字符串
String valueOf = String.valueOf(true);
System.out.println(valueOf);
String s = true+"";
System.out.println(s);
}
```