网站负责人备案采集照具体要求,湛江网吧,部署wordpress站点,在线seo关键词排名优化内部类
内部类是类中的五大成分之一#xff08;成员变量、方法、构造器、内部类、代码块#xff09;#xff0c;如果一个类定义在另一个类的内部#xff0c;这个类就是内部类。
当一个类的内部#xff0c;包含一个完整的事物#xff0c;且这个事物没有必要单独设计时成员变量、方法、构造器、内部类、代码块如果一个类定义在另一个类的内部这个类就是内部类。
当一个类的内部包含一个完整的事物且这个事物没有必要单独设计时就可以把这个事物设计成内部类。
比如汽车的内部有发动机发动机是包含在汽车内部的一个完整事物可以把发动机设计成内部类。
public class Car{//内部类public class Engine{}
}
内部类有四种形式分别是成员内部类、静态内部类、局部内部类、匿名内部类 。
1.1 成员内部类 成员内部类就是类中的一个普通成员类似于成员变量、成员方法。
public class Outer {private int age 99;public static String a黑马;// 成员内部类public class Inner{private String name;private int age 88;//在内部类中既可以访问自己类的成员也可以访问外部类的成员public void test(){System.out.println(age); //88System.out.println(a); //黑马int age 77;System.out.println(age); //77System.out.println(this.age); //88System.out.println(Outer.this.age); //99}public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}public void setAge(int age) {this.age age;}}
}
成员内部类如何创建对象格式如下
//外部类.内部类 变量名 new 外部类().new 内部类();
Outer.Inner in new Outer().new Inner();
//调用内部类的方法
in.test();
内部类访问成员的特点
1.既可以访问内部类成员、也可以访问外部类成员
2.如果内部类成员和外部类成员同名可以使用 类名.this.成员 区分 1.2 静态内部类
静态内部类其实就是在成员内部类的前面加了一个static关键字。静态内部类属于外部类自己持有。
public class Outer {private int age 99;public static String schoolName黑马;// 静态内部类public static class Inner{//静态内部类访问外部类的静态变量是可以的//静态内部类访问外部类的实例变量是不行的public void test(){System.out.println(schoolName); //99//System.out.println(age); //报错}}
}
静态内部类创建对象时需要使用外部类的类名调用。
//格式外部类.内部类 变量名 new 外部类.内部类();
Outer.Inner in new Outer.Inner();
in.test();
1.3 局部内部类
局部内部类是定义在方法中的类和局部变量一样只能在方法中有效。所以局部内部类的局限性很强一般在开发中是不会使用的。
public class Outer{public void test(){//局部内部类class Inner{public void show(){System.out.println(Inner...show);}}//局部内部类只能在方法中创建对象并使用Inner in new Inner();in.show();}
}
1.4 匿名内部类
相比于前面几种内部类匿名内部类就比较重要的。
我们还是先认识一下什么是匿名内部类
匿名内部类是一种特殊的局部内部类所谓匿名指的是程序员不需要为这个类声明名字。
下面就是匿名内部类的格式
new 父类/接口(参数值){Override重写父类/接口的方法;
}
匿名内部类本质上是一个没有名字的子类对象、或者接口的实现类对象。
比如先定义一个Animal抽象类里面定义一个cry()方法表示所有的动物有叫的行为但是因为动物还不具体cry()这个行为并不能具体化所以写成抽象方法。
public abstract class Animal{public abstract void cry();
}
接下来我想要在不定义子类的情况下创建Animal的子类对象就可以使用匿名内部类
public class Test{public static void main(String[] args){//这里后面new 的部分其实就是一个Animal的子类对象//这里隐含的有多态的特性 Animal a Animal子类对象;Animal a new Animal(){Overridepublic void cry(){System.out.println(猫喵喵喵的叫~~~);}}a.eat(); //直线上面重写的cry()方法}
}
需要注意的是匿名内部类在编写代码时没有名字编译后系统会为自动为匿名内部类生产字节码字节码的名称会以外部类$1.class的方法命名 匿名内部类的作用简化了创建子类对象、实现类对象的书写格式。 我们再来看一下匿名内部类在实际中的应用场景。
只有在调用方法时当方法的形参是一个接口或者抽象类为了简化代码书写而直接传递匿名内部类对象给方法。这样就可以少写一个类。比如看下面代码
public interface Swimming{public void swim();
}
public class Test{public static void main(String[] args){Swimming s1 new Swimming(){public void swim(){System.out.println(狗刨飞快);}};go(s1);Swimming s1 new Swimming(){public void swim(){System.out.println(猴子游泳也还行);}};go(s1);}//形参是Swimming接口实参可以接收任意Swimming接口的实现类对象public static void go(Swimming s){System.out.println(开始~~~~~~~~);s.swim();System.out.println(结束~~~~~~~~);}
}
二、枚举
2.1 认识枚举
枚举是我们以后在项目开发中偶尔会用到的知识。
枚举是一种特殊的类它的格式是
public enum 枚举类名{枚举项1,枚举项2,枚举项3;
}
其实枚举项就表示枚举类的对象只是这些对象在定义枚举类时就预先写好了以后就只能用这几个固定的对象。
既然枚举是一个类的话我们能不能在枚举类中定义构造器、成员变量、成员方法呢答案是可以的。来看一下代码吧。
public enum A{//定义枚举项X,Y,Z(张三); //枚举项后面加括号就是在执行枚举类的带参数构造方法。//定义空构造器public A(){}//成员变量private String name;//定义带参数构造器public A(String name){this.namename;}//成员方法public String getName(){return name;}...
}
虽然枚举类中可以像类一样写一些类的其他成员但是一般不会这么写如果你真要这么干的话到不如直接写普通类来的直接。
2.2 枚举的应用场景
枚举的应用场景是这样的枚举一般表示一组信息然后作为参数进行传输。
我们来看一个案例。比如我们现在有这么一个应用用户进入应用时需要让用户选择是女生、还是男生然后系统会根据用户选择的是男生还是女生推荐不同的信息给用户观看。
这里我们就可以先定义一个枚举类用来表示男生、或者女生
public class Constant{BOY,GRIL
}
再定义一个测试类完成用户进入系统后的选择
public class Test{public static void main(String[] args){//调用方法传递男生provideInfo(Constant.BOY);}public static void provideInfo(Constant c){switch(c){case BOY:System.out.println(展示一些信息给男生看);break;case GRIL:System.out.println(展示一些信息给女生看);break;}}
}
最终再总结一下枚举的应用场景枚举一般表示几个固定的值然后作为参数进行传输。
三、泛型
3.1 认识泛型
所谓泛型指的是在定义类、接口、方法时同时声明了一个或者多个类型变量如E称为泛型类、泛型接口、泛型方法、它们统称为泛型。比如我们前面学过的ArrayList类就是一个泛型类。
ArrayList集合的设计者在定义ArrayList集合时就已经明确ArrayList集合时给别人装数据用的但是别人用ArrayList集合时候装什么类型的数据他不知道所以就用一个E表示元素的数据类型。 当别人使用ArrayList集合创建对象时new ArrayListString就表示元素为String类型new ArrayListInteger表示元素为Integer类型。
我们总结一下泛型的作用、本质
1.泛型的好处在编译阶段可以避免出现一些非法的数据。
2.泛型的本质把具体的数据类型传递给类型变量。
3.2 自定义泛型类
泛型类在实际工作中一般都是源代码中写好我们直接用的就是ArrayListE这样的自己定义泛型类是非常少的。
自定义泛型类的格式如下
//这里的T,W其实指的就是类型变量可以是一个也可以是多个。
public class 类名T,W{}
接下来我们自己定义一个MyArrayListE泛型类模拟一下自定义泛型类的使用。注意这里重点仅仅只是模拟泛型类的使用所以方法中的一些逻辑是次要的也不会写得太严谨。
//定义一个泛型类用来表示一个容器
//容器中存储的数据它的类型用E先代替用着等调用者来确认E的具体类型。
public class MyArrayListE{private Object[] array new Object[10];//定一个索引方便对数组进行操作private int index;//添加元素public void add(E e){array[index]e;index;}//获取元素public E get(int index){return (E)array[index];}
}
接下来我们写一个测试类来测试自定义的泛型类MyArrayList是否能够正常使用
public class Test{public static void main(String[] args){//1.确定MyArrayList集合中元素类型为String类型MyArrayListString list new MyArrayList();//此时添加元素时只能添加String类型list.add(张三);list.add(李四);//2.确定MyArrayList集合中元素类型为Integer类型MyArrayListInteger list1 new MyArrayList();//此时添加元素时只能添加String类型list.add(100);list.add(200);}
}
3.3 自定义泛型接口
泛型接口其实指的是在接口中把不确定的数据类型用类型变量表示。定义格式如下
//这里的类型变量一般是一个字母比如E
public interface 接口名类型变量{}
比如我们现在要做一个系统要处理学生和老师的数据需要提供2个功能保存对象数据、根据名称查询数据要求这两个功能处理的数据既能是老师对象也能是学生对象。
首先我们得有一个学生类和老师类
public class Teacher{}
public class Student{}
我们定义一个DataT泛型接口T表示接口中要处理数据的类型。
public interface DataT{public void add(T t);public ArrayListT getByName(String name);
}
接下来我们写一个处理Teacher对象的接口实现类
//此时确定DataE中的E为Teacher类型
//接口中add和getByName方法上的T也都会变成Teacher类型
public class TeacherData implements DataTeacher{public void add(Teacher t){}public ArrayListTeacher getByName(String name){}
}
接下来我们写一个处理Student对象的接口实现类
//此时确定DataE中的E为Student类型
//接口中add和getByName方法上的T也都会变成Student类型
public class StudentData implements DataStudent{public void add(Student t){}public ArrayListStudent getByName(String name){}
}
在实际工作中一般也都是框架底层源代码把泛型接口写好我们实现泛型接口就可以了。
3.4 泛型方法
泛型方法的格式
public 泛型变量,泛型变量 返回值类型 方法名(形参列表){}
接下我们看一个泛型方法的案例
public class Test{public static void main(String[] args){//调用test方法传递字符串数据那么test方法的泛型就是String类型String rs test(test);//调用test方法传递Dog对象那么test方法的泛型就是Dog类型Dog d test(new Dog()); }//这是一个泛型方法T表示一个不确定的数据类型由调用者确定public static T test(T t){return t;}
}
3.5 泛型限定
泛型限定的意思是对泛型的数据类型进行范围的限制。有如下的三种格式
1.? 表示任意类型
2.? extends 数据类型 表示指定类型或者指定类型的子类
3.? super 数据类型 表示指定类型或者指定类型的父类 下面我们演示一下假设有Car作为父类BENZBWM两个类作为Car的子类代码如下
class Car{}
class BENZ extends Car{}
class BWN extends Car{}public class Test{public static void main(String[] args){//1.集合中的元素不管是什么类型test1方法都能接收ArrayListBWM list1 new ArrayList();ArrayListBenz list2 new ArrayList();ArrayListString list3 new ArrayList();test1(list1);test1(list2);test1(list3);//2.集合中的元素只能是Car或者Car的子类类型才能被test2方法接收ArrayListCar list4 new ArrayList();ArrayListBWM list5 new ArrayList();test2(list4);test2(list5);//2.集合中的元素只能是Car或者Car的父类类型才能被test3方法接收ArrayListCar list6 new ArrayList();ArrayListObject list7 new ArrayList();test3(list6);test3(list7);}public static void test1(ArrayList? list){}public static void test2(ArrayList? extends Car list){}public static void test3(ArrayList? super Car list){}
}
3.6 泛型擦除
什么是泛型擦除呢也就是说泛型只能编译阶段有效一旦编译成字节码字节码中是不包含泛型的。而且泛型只支持引用数据类型不支持基本数据类型。
四、常用API
APIApplication Programming interface意思是应用程序编程接口说人话就是Java帮我们写好的一些程序如类、方法等我们直接拿过来用就可以解决一些问题。
4.1 Object类
我们先来学习toString()方法。
public String toString()调用toString()方法可以返回对象的字符串表示形式。默认的格式是“包名.类名哈希值16进制”
假设有一个学生类如下
public class Student{private String name;private int age;public Student(String name, int age){this.namename;this.ageage;}
}
再定义一个测试类
public class Test{public static void main(String[] args){Student s1 new Student(赵敏,23);System.out.println(s1.toString()); }
}
打印结果如下 如果在Student类重写toString()方法那么我们可以返回对象的属性值代码如下
public class Student{private String name;private int age;public Student(String name, int age){this.namename;this.ageage;}Overridepublic String toString(){return Student{name‘name’, ageage};}
}
运行测试类结果如下 接下来我们学习一下Object类的equals方法
public boolean equals(Object o)判断此对象与参数对象是否相等
我们写一个测试类测试一下
public class Test{public static void main(String[] args){Student s1 new Student(赵薇,23);Student s2 new Student(赵薇,23);//equals本身也是比较对象的地址和没有区别System.out.println(s1.equals(s2)); //false//比较对象的地址System.out.println(s1s2); //false}
}
但是如果我们在Student类中把equals方法重写了就按照对象的属性值进行比较
public class Student{private String name;private int age;public Student(String name, int age){this.namename;this.ageage;}Overridepublic String toString(){return Student{name‘name’, ageage};}//重写equals方法按照对象的属性值进行比较Overridepublic boolean equals(Object o) {if (this o) return true;if (o null || getClass() ! o.getClass()) return false;Student student (Student) o;if (age ! student.age) return false;return name ! null ? name.equals(student.name) : student.name null;}
}
再运行测试类效果如下 接下来我们学习Object类的clone()方法克隆。意思就是某一个对象调用这个方法这个方法会复制一个一模一样的新对象并返回。
clone方法是Object类中的一个被protected和native修饰的方法,被native就代表它的实现源码是用c实现的,只不过是我们无法去修改它的代码罢了。
public Object clone()克隆当前对象返回一个新对象
想要调用clone()方法必须让被克隆的类实现Cloneable接口。如我们准备克隆User类的对象代码如下
public class User implements Cloneable{private String id; //编号private String username; //用户名private String password; //密码private double[] scores; //分数public User() {}public User(String id, String username, String password, double[] scores) {this.id id;this.username username;this.password password;this.scores scores;}//...get和set...方法自己加上Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
接着我们写一个测试类克隆User类的对象。
public class Test {public static void main(String[] args) throws CloneNotSupportedException {User u1 new User(1,zhangsan,wo666,new double[]{99.0,99.5});//调用方法克隆得到一个新对象User u2 (User) u1.clone();System.out.println(u2.getId());System.out.println(u2.getUsername());System.out.println(u2.getPassword());System.out.println(u2.getScores()); }
}
我们发现克隆得到的对象u2它的属性值和原来u1对象的属性值是一样的。
上面演示的克隆方式是一种浅克隆的方法浅克隆的意思拷贝出来的对象封装的数据与原对象封装的数据一模一样引用类型拷贝的是地址值。如下图所示 还有一种拷贝方式称之为深拷贝拷贝原理如下图所示 下面演示一下深拷贝User对象
public class User implements Cloneable{private String id; //编号private String username; //用户名private String password; //密码private double[] scores; //分数public User() {}public User(String id, String username, String password, double[] scores) {this.id id;this.username username;this.password password;this.scores scores;}//...get和set...方法自己加上Overrideprotected Object clone() throws CloneNotSupportedException {//先克隆得到一个新对象User u (User) super.clone();//再将新对象中的引用类型数据再次克隆u.scores u.scores.clone();return u;}
}
4.2 Objects类
Objects是一个工具类提供了一些方法可以对任意对象进行操作。主要方法如下 下面写代码演示一下这几个方法
public class Test{public static void main(String[] args){String s1 null;String s2 itheima;//这里会出现NullPointerException异常调用者不能为nullSystem.out.println(s1.equals(s2));//此时不会有NullPointerException异常底层会自动先判断空System.out.println(Objects.equals(s1,s2));//判断对象是否为null等价于System.out.println(Objects.isNull(s1)); //trueSystem.out.println(s1null); //true//判断对象是否不为null等价于!System.out.println(Objects.nonNull(s2)); //trueSystem.out.println(s2!null); //true}
}
4.3 基本类型包装类
为什么要学习包装类呢因为在Java中有一句很经典的话万物皆对象。Java中的8种基本数据类型还不是对象所以要把它们变成对象变成对象之后可以提供一些方法对数据进行操作。
Java中8种基本数据类型都用一个包装类与之对一个如下图所示 我们学习包装类主要学习两点
1.创建包装类的对象方式、自动装箱和拆箱的特性
2. 利用包装类提供的方法对字符串和基本类型数据进行相互转换
我们先来学习创建包装类对象的方法以及包装类的一个特性叫自动装箱和自动拆箱。我们以Integer为例其他的可以自己学都是类似的。
//1.创建Integer对象封装基本类型数据10
Integer a new Integer(10);//2.使用Integer类的静态方法valueOf(数据)
Integer b Integer.valueOf(10);//3.还有一种自动装箱的写法意思就是自动将基本类型转换为引用类型
Integer c 10;//4.有装箱肯定还有拆箱意思就是自动将引用类型转换为基本类型
int d c;//5.装箱和拆箱在使用集合时就有体现
ArrayListInteger list new ArrayList();
//添加的元素是基本类型实际上会自动装箱为Integer类型
list.add(100);
//获取元素时会将Integer类型自动拆箱为int类型
int e list.get(0);
在开发中经常使用包装类对字符串和基本类型数据进行相互转换。
1.把字符串转换为数值型数据包装类.parseXxx(字符串)
public static int parseInt(String s)把字符串转换为基本数据类型
2.将数值型数据转换为字符串包装类.valueOf(数据)
public static String valueOf(int a)把基本类型数据转换为
写一个测试类演示一下
//1.字符串转换为数值型数据
String ageStr 29;
int age1 Integer.parseInt(ageStr);String scoreStr 3.14;
double score Double.prarseDouble(scoreStr);//2.整数转换为字符串以下几种方式都可以挑中你喜欢的记一下
Integer a 23;
String s1 Integer.toString(a);
String s2 a.toString();
String s3 a;
String s4 String.valueOf(a);