形式参数与返回值:
形式参数的类型:1)基本类型:使用时没有什么区别,只要形参是什么类型就给它传什么类型的数据即可;
2)引用类型:String特殊的引用类型,使用时与基本类型一致
(1)具体类:需要创建具体类的对象进行传值;
(2)抽象类:需要创建该抽象类的子类对象(抽象类多态,使用匿名内部类)
(3)接口类:需要创建该接口的子实现类(接口类多态,使用匿名内部类)
返回值的类型:1)基本类型:需要返回什么数据类型就给返回什么数据类型;
2)引用类型:(1)具体类:返回该具体类的对象;
(2)抽象类:返回该抽象类的子类对象;
(3)接口类:返回该接口的子实现类对象;
内部类:在一个类(A)的内部定义另一个类(B),则B就是A的内部类
例:class A {
private int num = 10;
class B {
System.out.println(num);
}
}
内部类的访问特点:1)内部类可以访问外部类的成员,包括私有成员都可以访问;
2)外部类想要访问内部类的成员时,需要创建内部类对象来访问内部类成员;
内部类按所在的位置分类:
1)成员内部类:存在于外部类的成员位置上;
class A {
private int num = 10;
(static) class B {
System.out.println(num);
}
}
外部类访问成员内部类时创建对象的方法:
(1)非静态内部类:外部类名 . 内部类名 对象名 = new 外部类名(). new 内部类名();
例:A.B ab = new A() . new B();
(2) 静态内部类:外部类名 . 内部类名 对象名 = new 外部类名 . 内部类名();
外部类名.内部类名.(内部类)成员变量 / 方法
例: A.B ab = new A.B ();
成员内部类的修饰符:
private 修饰:为了保证数据的安全性,只能通过在外部类的方法里创建内部类的对象进行访问;
static 修饰:方便调用;可以通过 外部类名.内部类名. 成员变量/方法 直接调用
2)局部内部类:存在于方法内的类;可直接访问外部类的成员,包括私有;
例:
class A {
private int num = 10;
public void method(){
final int num2 = 20; //JDK1.8以前必须使用 final 修饰,否则报错;
class B {
System.out.println(num);
System.out.println(num2);
}
}
}
***** 面试题:为什么要用 final 修饰局部变量?
答: 局部内部类想要访问局部变量时,局部变量必须使用 final 修饰;
因为局部变量是随着方法的调用而存在的,随着方法的调用完毕而消失的,
而内部类对象在使用后却不会立即消被GC回收掉,
这时就会出现当方法调用完毕后,当局部内部类还需要访问该局部变量,所以程序就会报错,
所以这时就需要将局部变量变成常驻内存的变量(常量),所以用 final 修饰;
匿名内部类:顾名思义即没有名字的内部类;
匿名内部类存在的前提:必须存在一个类 或者 接口
格式:
new 类名 / 接口名{
重写 类 或 接口中的方法;
。。。
};逗号结尾
*********匿名内部类面试题:
按照要求,补齐代码
interface Inter {
void show();
}
class Outer {
//补齐代码
Outer.method().show();
// 分析 1)Outer.method() 外部类名可直接调用,说明该方法被 static 修饰;
2)Outer.method() 调用 method()后还能调用show()方法,说明返回的是一个对象(接口);
3)返回的是一个接口类型,实际返回的是的该接口的子实现类对象,根据题目要求应该采用匿名内部类来实现;
public static Inter method(){
return new Inter{ // 匿名内部类
@override
public void show(){
System.out.println(" Hello World");
}
};
}
}
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
要求在控制台输出”HelloWorld”
**********面试题:
控制台分包输出30,20,10
注意: 内部类与外部类之间没有继承关系!(无法用 super )
外部类访问本类成员变量
方式1: 外部类对象(匿名对象的方式).成员变量名称;
方式2: 外部类的this限定:Outer.this.num:可以访问外部类的成员变量(推荐使用)
class Outer{
private int num = 10 ;
//成员内部类
class Inner{
//内部类的成员变量
int num = 20 ;
public void show() {
//局部变量
( final ) int num = 30 ;
//补全代码
System.out.println(num);
System.out.println(this.num); //访问当前类对象的成员变量
// System.out.println(new Outer().num);
//外部类限定this
System.out.println(Outer.this.num);
}
}
}
public class OuterTest2 {
public static void main(String[] args) {
//补全代码
//外部类名.内部类名 对象名 = 外部类对象.内部类对象;
Outer.Inner oi = new Outer().new Inner() ;
oi.show();
}
}
常用类:
1)Object类:所有类的根类,所有类都默认继承自Object类
常用方法: (1)public int hashCode():返回的是该对象的哈希码值(逻辑地址)
该哈希码值是根据对象的地址值计算而来的,一般来说不同对象的哈希值不同;
(2)public final Class getClass(): 返回此对象的运行类
getClass().getName() : 可获得该运行类的全类名;(包名.类名)
(3)public String toString(): 返回该对象的字符串表示(地址值);
相当于:getClass().getName()+@+Integer.toHexStirng(hashCode(此对象));
默认输出是一个地址值,所以建议子类都重写该方法;
(4)public boolean equals(): 比较两对象是否相等;
默认比较的是引用(地址值),所以建议子类重写该方法,重写之后比较的就是对象的内容是否相等
(5)protected finalize(): 当垃圾回收机制确定该对象没有任何的引用之后,
便会由对象的垃圾回收机制调用此方法进行回收;主要针对堆内存;
(6)public Object clone(): 创建并返回该对象的一个副本(复制),
这种克隆机制十分高效,且两个对象互相独立;
前提: 该类必须实现 Cloneable 接口,才能调用此方法;
自定义类实现克隆步骤:
A:自定义类实现Cloneable接口,这是一个标记性接口,实现这个接口的类的对象可以实现自我克隆。
B:自定义类中重写Object类的clone()方法。
C:重写clone()方法时通过 super.clone() 调用Object类的clone()方法来得到该对象的副本,并返回该副本。
注意:
A:克隆和两个引用指向同一个对象的区别?
B:Object类clone()方法虽然简单,易用,但仅仅是一种”浅克隆”,它只克隆该对象所有的Field值,
不会 对引用类型的Field所引用的对象进行克隆。开发中,我们也可以实现对象的”深度克隆”。
*****面试题: == 与 equals
== :
基本数据类型:比较的是值;
引用类型:比较的是地址值;
equals:
重写之前:Object类中equals()比较的是地址值;
重写之后:比较的是对象的“内容”,如String中的euqals()方法
2)Scanner类:用于键盘录入
常用方法:public XXX nextXXX() : 录入下一个XXX数据类型的数据
public boolean hasNextXXX(): 判断录入的数据下一个是否是XXX这类型的数据
注意:
// 先录入int类型的数据,在录入字符串
int num = sc.nextInt() ;
Scanner sc2 = new Scanner(System.in) ;
String str = sc2.nextLine() ;
System.out.println("num:"+num+",str:"+str);
会出现:输入数字后直接输回车它就直接打印出来了
//10
//num:10,str:
原因:系统默认把回车当作是一个字符串输入了,直接就略过了;但该字符串的长度为 0 ;
解决:在输入数字之后,再重新创建Scanner对象接收一次;
3)String 类:由多个字符组成的一串字符,可以看成是一个字符数组
String:特殊的引用类型
字符串是常量;一旦给它们赋值之后就不能更改。
常量是在方法区中:字符串常量池 : 前提:将字符串常量直接赋值的形式
例:
String str = "abc" ; ==> 相当于String str = new String("abc")
构造方法:
String() : 空参构造
String(byte[] bytes): 将字节数组-->String 数据
String(byte[] bytes, int offset, int length): 将字节数组的一部分转换字符串
String(char[] value) : 将字符数组转换成字符串
String(char[] value, int offset, int length): 将字符数组的一部分转换字符串
public String(String original) : 创建一个字符串对象:传递字符串常量
常用的成员方法:
public int length() : 获取字符串的长度;
public boolean equals(Object anObject) : 比较字符串的内容是否相同
public boolean equalsIgnoreCase(String anotherString): 比较内容是否相同,忽略大小写
public boolean contains(String s): 判断大字符串中是否包含一个子字符串
public boolean startsWith(String prefix): 判断字符串是以...开头
public boolean endsWith(String suffix): 判断字符串是以...结尾
public boolean isEmpty() : 判断字符串是否为空
两个区别:
前者:表示当前s对象是一个空内容
后者:表示空对象
String s ="" ; str.length()=0
String s = null ; 没有长度
******面试题
String s = new String(“hello”)和String s = “hello”;的区别?
答:String s = "hello" : 创建了一个对象;字符串常量池;
String s = new String(“hello”):创建了两个对象;堆内存和字符串常量池
图解:
******笔试题
数组中有没有length(),字符串中有没有length(),集合中有没有length()?
数组length属性,字符串中有,集合没有-->size()方法
注意:
字符串变量相加,是先开辟空间(不是先相加),再看常量池中是否有这个字符串常量..
字符串常量相加,是先拼接(先相加),再开辟空间
String s7 = "hello"; // 存在于字符串常量池
String s8 = "world";
String s9 = "helloworld";
System.out.println(s9==s7+s8); //先开辟空间,再比较 flase
System.out.println(s9.equals(s8+s7)); //先开辟空间,再比较 false
String s10 = "helloworld"; // 存在于字符串常量池
System.out.println(s10=="hello"+"world"); //先合并比较,再开辟空间 true
System.out.println(s10.equals("hello"+"world")); //先合并比较,再开辟空间 true