Java基础知识 13
局部内部类
详细程序请参考:E:\Java project\20200425-匿名对象类-练习
局部内部类:把一个类定义到另一个类的方法中。内部类可以直接访问外部类的成员,包括私有的。局部内部类,在外界没有直接创建其对象的语法,
public class Mytest {
public static void main(String[] args) {
//局部内部类:把一个类定义到另一个类的方法中
//内部类可以直接访问,外部类的成员,包括私有的。
//局部内部类,在外界没有直接创建其对象的语法
Outer outer = new Outer();
outer.num=100;
System.out.println(outer.num);//100
outer.show();
}
}
class Outer{
int num=20;
private double a=3.14;
public void show(){
class Inner{
int b=100;
double c=500;
public void neishow(){
System.out.println("内show方法");
System.out.println(num);
System.out.println(a);
}
public void neitest(){
System.out.println(b);
}
}
Inner inner = new Inner();
inner.neishow();
inner.neitest();
}
public void waitest(){
System.out.println("外test方法");
}
}
局部内部类访问外部类的外部类的局部变量,这个局部变量要加final修饰,使其变为一个常量,JDK1.8已经默认加上了。因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立刻从堆内存中消失,还要使用那个变量,为了能使数据继续使用,我们会用final修饰,这样数据就是一个变量。
public class Mytest {
public static void main(String[] args){
new Wai().waishow(300);
}
}
class Wai{
int num=100;//成员变量
public void waishow(final int i){
final int a=200;//局部变量
//局部内部类
class Nei{
int j=500;
public void neishow(){
num=600;
System.out.println(num);//600
System.out.println(a);//200
System.out.println(i);//300
System.out.println(j);//500
}
}
Nei nei = new Nei();
nei.neishow();
}
}
匿名内部类
详细程序请查看:E:\Java project\20200425-匿名对象类-练习
它是局部内部类的一种简化写法。
匿名内部类的本质:匿名内部类本质上是一个对象,是继承了该抽象类或者实现了该接口的子类对象。
new 类名或接口名{
重写方法;
} //alt+enter,纠错重写抽象类中的方法
public class Mytest {
public static void main(String[] args) {
//匿名内部类:他是局部内部类的一种简化写法。
//匿名内部类的本质:匿名内部类本质上是一个对象。是继承了该抽象类或实现了该接口的子类的匿名对象。
//我想要得到一个抽象类MyClass的子类对象。
// MyClass aa = new AA();
//aa.aa();
//我想要得到一个抽象类MyClass的子类对象。我们可以采用匿名内部类,来得到一个抽象类的子类对象。
new Myclass(){
@Override
public void a() {
System.out.println("重写方法a");
}
}.a();
new Myclass(){
@Override
public void a() {
System.out.println("再次重写方法a");
}
}.a();
Myclass myclass = new Myclass(){
@Override
public void a() {
System.out.println("第三次重写方法a");
}
};
myclass.a();
}
}
abstract class Myclass{
public abstract void a();
}
匿名内部类的应用:可以作为参数来传递,或者作为返回值返回,当你以后看到一个方法的形参,要一个接口的类型,你就可以传递一个该接口的子类对象。
public class Mytest {
public static void main(String[] args) {
//匿名内部类的应用:可以作为参数来传递,或者作为返回值返回,
//当你以后看到看到一个方法的形参,要一个接口类型,你就可以传递一个该接口的子类对象
Zi zi = new Zi();
set(zi);
System.out.println("---------------------");
//使用匿名对象来进行传参
set(new Zi(){
@Override
public void a() {
System.out.println("使用匿名对象来进行传参");
}
});
FU fu=new Zi(){
@Override
public void a() {
System.out.println("使用匿名对象来进行传参2");
}
};
System.out.println("---------------------");
set(fu);
}
public static void set(FU a){
a.a();
}
}
interface FU{
void a();
}
class Zi implements FU{
@Override
public void a() {
System.out.println("重写了父类接口的方法");
}
}
当你以后看到一个方法的返回值类型要一个接口类型,你要返回一个该接口的子类对象。
public class Mytest2 {
public static void main(String[] args) {
new MyInterface(){
@Override
public void aa() {
System.out.println("重写接口中的aa方法");
}
}.aa();
//MyInterface myInterface = new MyInterface()
//使用多态去调用这个aa方法,多态的父类引用指向子类对象。
MyInterface myInterface = new MyInterface() {
@Override
public void aa() {
System.out.println("第二次重写接口中的aa方法");
}
};
myInterface.aa();
}
}
interface MyInterface{
public static final int a=200;//接口中的公共静态常量
public abstract void aa();
}
Object类
详细程序请参考:E:\Java project\20200425-Object-类-练习
API:应用程序接口,Application Programming Interface
Object类:它是所有类的顶层父类,所有的类都是直接或间接的继承自他。java.long包下的类,无需要导包。new对象.调用方法 Object obj=new Object();
Object类中常用的方法:
(1)获取该对象的哈希码值,hashcode(),返回该对象的哈希码值,默认情况下,该方法会根据对象的地址计算,不同对象的哈希码值是不一样的。
public class Mytest extends Object{
public static void main(String[] args) {
// Application Programming Interface API
//Object 类:他是所有类的顶层父类,所有的类都是直接或间接继承自他。
//创建Object类的对象
//java.lang 包下的类,无需要导包
//new 对象 调方法
Object obj = new Object();
System.out.println(obj);//地址值
//获取该对象的哈希码值。
//a:返回该对象的哈希码值。默认情况下,该方法会根据对象的地址来计算。
//不同对象的哈希码值也是不一样的。
int code = obj.hashCode();
System.out.println(code);
System.out.println("----------------");
Object obj2 = new Object();
System.out.println(obj2);//地址值
int code1 = obj.hashCode();
System.out.println(code1);
}
}
(2)getClass()方法,Java万物皆对象, object.java----->object.class(字节码文件),加载进内存后,他要把object.class这个文件也要看做对象,就会为object.class文件创建对象,这个对象就是class,我们只是把这字节码文件中的对象获取出来用。
getClass()获取这个类的字节码文件对象。object.class字节码文件就一份,你一加载进内存,九尾这个字节码文件创建了一个对象,你不管通过该类的哪个对象去获取这个类的字节码文件,都是同一个字节码对象。
public class Mytest2 extends Object{
public static void main(String[] args) {
//Java 万物皆对象
//object.java----->object.class(字节码文件)加载进内存后,他要把object.class这个文件也要看做对象,
//就会为object.class文件创建对象,这个对象就是class,我们只是把字节码文件对象获取出来用
Object obj = new Object();
//getclass()获取这个类的字节码文件对象
Class aClass = obj.getClass();
Object obj1 = new Object();
//object.class字节码文件就一份,你一加载进内存,就为这个字节码文件创建了一个对象,
//你不管通过该类的哪个对象去获取这个类的字节码文件,都是同一个字节码对象。
Class aClass1 = obj1.getClass();
System.out.println(obj==obj1);
System.out.println(aClass == aClass1);
System.out.println("=====================");
Object obj2 = new Object();
//getclass()获取这个类的字节码文件对象
Class aClass2 = obj2.getClass();
System.out.println(obj == obj2);
System.out.println(aClass == aClass2);
}
}
(3)返回该对象的字符串表示 toString() 这个toString()可以省略不写。
其实有很多类,也重写了Object类中的toString方法,当你以后输出一个对象后,输出的不是地址值,说明toString方法被重写了。
public class Student extends Object{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "姓名:"+this.name+"======="+"年龄:"+this.age;
}
public String show(){
return "姓名:"+this.name+"======="+"年龄:"+this.age;
}
}
public class Mytest4 {
public static void main(String[] args) {
Student student = new Student("刘能",50);
System.out.println(student.toString());
System.out.println(student.show());
System.out.println("---------------------");
Student student1 = new Student("尼古拉斯赵四", 48);
System.out.println(student1.toString());
System.out.println(student1.show());
}
}
(4)可以用Object类中的equals()方法来比较两个对象的地址值是否相同
boolean b=obj1.equals(obj2);
System.out.println(b);
使用equals()方法老是比较两个对象两个对象的地址值是否一样,意义不大。instanceof这个比较运算符,可以判断一个对象(引用)是不是该类型的一个对象(引用)。
我们比较两个字符串字面上的内容是否相同,要使用equals()方法比较,equals方法是Object类中的一个方法,这个方法默认在比较两个对象的地址值是否相同。
== 号 和equals()方法的区别:
1.== 是一个比较运算符,可以比较基本数据类型,也可以比较引用数据类型。
2.== 比较基本数据类型,是比较两个值是否相同
3.== 比较引用数据类型,比较的是两个对象的地址值,是否相同
import java.util.Objects;
public class Teacher extends Object{
private String name;
private int age;
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public int hashCode() {
return Objects.hash(name,age);
}
@Override
public boolean equals(Object obj) {
if (this==obj) {
return true;
}
//instanceof
//Teacher.class--->字节码文件对象 Dog.class--->字节码文件对象
//t1.getClass==t2.getClass()
if (obj==null||this.getClass()==obj.getClass()){
return false;
}
//向下转型
Teacher teacher=(Teacher) obj;
return this.age==teacher.age&&this.equals(name);
}
@Override
public String toString() {
return "姓名:"+this.name+"==="+"年龄:"+this.age;
}
}
-------------------------------------
public class Mytest {
public static void main(String[] args) {
// equals()方法是Object类中的一个方法,这个方法默认在比较两个对象的地址值是否相同。
Teacher t1 = new Teacher("谢飞机",15);
Teacher t2 = new Teacher("谢飞机",15);
System.out.println(t1 == t2);
System.out.println(t1.equals(t2));
System.out.println("------------------");
// == 号 和equals()方法的区别
// == 是一个比较运算符,可以比较基本数据类型,也可以比较引用数据类型。
// == 比较基本数据类型,是比较两个值是否相同
//== 比较引用数据类型,比较的是两个对象的地址值,是否相同 System.out.println(t1==t2);
int a=100;
int b=200;
System.out.println(a==b);
//equals是Object类中的一个方法 ,他只能比较引用数据类型。默认比较的是两个对象的地址值是否相同。
//但是我们自定义的类 ,或者是,其他一些类,可能会重写equals()方法。
}
}
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public boolean equals(Object obj) {
//Object obj=dog;
//按照我们自己的比较方式来比较,比较两个对象的成员变量值是否一样。
//如是自己跟自己比较
if (obj==null) {
return false;
}
if (this==obj){
return true;
}
//我们在向下转型时判断这个对象 他是不是Student类型的对象。如果不是就直接返回false 不要向下转型。
// instanceof 这个比较运算符,可以判断一个对象(引用)是不是该类型的一个对象(引用)
if(!(obj instanceof Student)) {
return false;
}
//向下转型
Student s2=(Student) obj;
//我们比较两个字符串字面上的内容是否相同,要使用equals方法来比较。
return this.name.equals(s2) & this.age==s2.age;
}
}
--------------------------------------------------
public class Mytest {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
//判断两个对象是否相同
System.out.println(obj1==obj2);
//我们可以采用Object类中的equals方法来比较两个对象的地址值是否相同
boolean b = obj1.equals(obj2);
System.out.println(b);
System.out.println("-------------------");
Student s1 = new Student("小明", 15);
Student s2 = new Student("小红", 14);
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
System.out.println("-------------------");
//我想比较两个对象的成员变量的值是否一样,如果一样我认为这两个对象相等。
//子类对父类equals方法的默认比较方式,不满意了。那子类可以按照他的比较方式去重写。
//我们的子类想要比较两个对象的成员变量值是否一样。
Teacher teacher = new Teacher();
boolean equals = s1.equals(teacher);
System.out.println(equals);
System.out.println("-------------------");
//我们以后在写一个方法时,除了要考虑主要的逻辑实现。
//还得考虑这个方法的健壮性(考虑周全),还得考虑方法的执行效率
boolean equals1 = s1.equals(s1);
System.out.println(equals1);
}
}
class Teacher{
}
(5)clone()方法,克隆一个对象。
如果你要克隆一个对象,那么这个对象的类,必须实现一个cloneable这个即可,那么这个对象才会被支撑。
对象的浅克隆也不会调用到构造方法的,cloneable接口中没有任何一个抽象方法,像这种接口,我们称之为标记接口,等于给类打个标记,告诉虚拟机,此类的对象想要进行克隆操作。
class Dog extends Object implements cloneable{}
对象的浅克隆就是克隆一个对象的时候,如果被克隆的对象中维护了另一个对象,这时候只是克隆另一个对象的地址,而没有把另一个对象也克隆一份。
public class Mytest {
public static void main(String[] args) throws CloneNotSupportedException {
Food food = new Food("米饭");
Person person = new Person("陕西人",45,food);
System.out.println(person);
person.food.shiwu="油泼面";
Person person1= (Person) person.clone();
System.out.println(person1);
person1.food.shiwu="馒头";
//克隆person
/* 对象的浅克隆就是克隆一个对象的时候,如果被克隆的对象中维护了另外一个类的对象,
这时候只是克隆另外一个对象的地址,而没有把
另外一个对象也克隆一份。*/
//打印食物名称
System.out.println(person.food.shiwu);
System.out.println(person1.food.shiwu);
}
}
class Person extends Object implements Cloneable{
String name;
int age;
Food food;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, Food food) {
this.name = name;
this.age = age;
this.food = food;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Food{
String shiwu;
public Food(String shiwu){
this.shiwu=shiwu;
}
}
对象的浅克隆内存图理解:
Scanner()类
详细程序请参考:E:\Java project\20200426-Scanner-练习
一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器。
Scanner(InputStream source)构造一个新的Scanner,它生成的值是从指定的输入流扫描。
InputStream 字节输入流
InputStream in = System.in; //in “标准输入流”。此流已打开并准备提供输入数据,通常,此流对应于键盘输入。
import java.io.InputStream;
import java.util.Scanner;
public class ScannerDemo {
public static void main(String[] args) {
// Scanner 一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器。
// Scanner(InputStream source) 构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。
// InputStream 字节输入流
InputStream in = System.in;//in “标准”输入流。此流已打开并准备提供输入数据。通常,此流对应于键盘输入
Scanner scanner = new Scanner(in);
System.out.println("------------------");
Scanner sc = new Scanner(System.in);
//Scanner 里面的常用的方法
//录入各种类型数据的方法 nextXXX();
//判断录入的数据类型的方法 hasNextXXX();
//录入数字
int i = sc.nextInt();
double v = sc.nextDouble();
long l = sc.nextLong();
//录入布尔类型
boolean b = sc.nextBoolean();
//录入字符串
String s = sc.nextLine();
}
}
当我们先录入一个整数,在录入完一个字符串时,发现字符串并没有录入进去,因为你输入完数字后,敲了回车,那么这个回车换行其实被当作字符。
然后说nextLine()方法,把回车换行录入进去了。这种现象其实并不是咱们想要的,怎么解决?
(1)可以在录入完整数后,在录入字符串之前,重新再创建一个Scanner对象。
(2)你可以在录入字符串时,换一个方法next();
区别:nextLine()和next()方法的区别:
(1)next()方法,假如遇到我们输入的一行字符串中,字符串中间有空格,遇到空格,那么后面的内容就不再输入。
(2)nextLine()方法,会录入一整行的数据。
可以用hasnext()方法来预判一下用户输入的类型。
import java.util.Scanner;
public class ScannerDemo2 {
public static void main(String[] args) {
/*Scanner sc = new Scanner(System.in);
System.out.println("请输入一个整数");
int i = sc.nextInt();
System.out.println(i);
System.out.println("请输入一个字符串");
String j = sc.nextLine();
System.out.println(j);*/
//当我们先录入一个整数,在录入一个字符串时,发现字符串并没有录入进去。
//因为你输入完数字后,敲了回车,那么这个回车换行其实被当做字符
//然后 nextLine() 这个方法,把回车换行录入进去了。这种现象不是你想要的。那怎么解决。
//解决方式1. 你可以录完整数,在录入字符串之前,重新再创建一个Scanner对象。
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个整数");
int i = sc.nextInt();
System.out.println(i);
sc=new Scanner(System.in);
System.out.println("请输入一个字符串");
String j = sc.nextLine();
System.out.println(j);
System.out.println("=======================");
//解决方式2:你可以再录入字符串时,换一个方法 next()
/*Scanner sc = new Scanner(System.in);
System.out.println("请输入一个整数");
int i = sc.nextInt();
System.out.println(i);
System.out.println("请输入一个字符串");
String j = sc.next();
System.out.println(j);*/
}
}