1.面试题,
1.1super和this的区别:
super:代表父类的空间标识(父类对象的地址值引用)
this:代表当前本类的对象的地址值引用
访问区别
访问成员变量:
this.变量名 :访问当前类的成员变量
super.变量名;访问的父类的成员变量
访问构造方法:
this() ; 访问当前类的无参构造方法
super() ; 访问的是父类的无参构造方法
this(xx) ; 访问的是当前类的有参构造方法
super(xx) ; 访问的是父类的有参构造方法
访问成员方法
this.方法名() ; 访问的是当前类的成员方法
super.方法名() ;访问的是父类的成员方法
1.2什么时候使用继承:
如果B类是A类的一种,或者A类是B类的一种,这个时候就可以使用继承.不要为了使用部分功能,而使用继承,因为继承的本事弊端:具有局限性;
1.3接口和抽象类的区别;
1) 成员的的区别;
接口:
成员变量:只能是常量,存在默认修饰符 public static final可以省略.
成员方法:只能是抽象方法,存在默认修饰符 public abstract 可以省略;
构造方法,接口没有
抽象类:
成员变量:既可以是常量,也可以是变量
成员方法:既可以存在抽象方法,而且抽象方法abstract不能省略,也可以存在非抽象方法.
构造方法:存在:无参/有参,继承关系,先让父类初始化,然后是子类初始化(分层初始化)
2)关系的区别
类与类之间的关系:继承关系 extends,只支持单继承,不支持多继承,但是可以多层继承.
类与类之间的关系:实现关系 implements,一个类继承另一个类的同时,可以实现多个接口;
接口与接口之间的关系:继承关系,不仅支持单继承,也可以多继承,也可以多层继承.
3)设计理念的区别:
抽象类---存在继承关系extends,继承体现的是"is a"的关系;
接口---存在实现关系implements,仅仅是将额外功能提供相关的事物,这个事物要具备额外功能.
必须实现这个接口,体现的是一种"like a"的关系.
1.4 获取一个类的字节码文件对象的方式有几种?
1)Object的方法 public final Class getClass()
2)任意Java类型的class属性
1.5 局部内部类访问局部变量的时候,有什么要求?为什么?
要求当前的局部变量为常量:加入final修饰 ,为什么
jdk8 jvm已经做了内存优化:通过反编译工具查看:num2:自动带上final修饰(默认,省略了)
jdk7以前(包含jdk7):局部内部类访问局部变量,前面必须显示的加入final修饰
局部变量的生命周期随着方法的调用而存在,随着方法调用结束而消失; 但是局部变量还在被局部内部类的成员方法在使用,局部类的对象不会立即消失,需要等待GC回收,需要将这个变量变成 常量,保证一直可以访问到!
1.6数组中没有length(),字符串String类中有没有length(),集合中有没有length()?
数组中没有length(),只有length属性.
• String:有
• 集合没有: 获取长度使用size();
• null :空值,没有对象,引用数据类型的默认值.
• String s=null;
• String s="";空字符序列,有,存在对象
1.7 String s = "hello" ;和String s2 = new String("hello") ;两个有什么区别,分别创建了几个对象!
共同点:都是在创建一个字符串对象"hello"
但是内存执行不一样
前者:只是在常量池中开辟空间,创建一个对象 :推荐这种方式,节省内存空间!
后者:在堆中开辟空间,而且里面存在常量----常量池中标记 ,创建两个对象
1.8StringBuff 和StringBulider有啥区别?
共同点:两者都是字符串区,支持可变的字符序列,而且痘都有互相兼容的API;
不同点:
• StringBuffer;线程安全的类,多线程环境下使用居多-----同步(安全)-----执行效率低
• StringBuilder:线程不安全的类,单线程使用居多----不同步(不安全)-----执行效率很高;
1.9String和StringBuffer有啥区别?
String是常量:一旦被赋值,其值不能被更改,他的不可变得字符序列
• 开发中:前端提交后台的数据----String(他的功能远远大于StringBuffer)
• 作为形式参数,形式参数的改变不会影响实际参数,特殊的引用类型,和基本数据类型最为形式参数的效果是一样的.
StringBuffer是可变的字符序列,线程安全的类,同步,执行效率低,单线程程序中的使用StringBuilder替代StringBuffer.
• 字符窜缓冲区 里面存储的字符序列=--------还需要转换成String类型.
• 作为形式参数,形式参数的改变直接会影响实际参数.
2.抽象
定义:在现实事物中,将比较概括性的事物统称为"抽象的事物".
举例: 猫和狗是具体的动物了,他们都继承自动物类,将动物就可以看成是一个抽象的事物;
猫和狗具体的功能应该具体体现,在动物事物中,应该给出一个声明即可,不需要具体体现!
格式:abstract class类名{}
注意事项:(1)在一个类中,如果当前类中存在抽象功能(方法),那么这个类必须是抽象类;
(2)一个抽象类中,不一定都是抽象方法;
抽象方法:没有方法体的一个成员方法,并且携带一个关键字abstract
权限修饰符 abstract 返回值类型 方法名(形式参数列表);
(3)抽象类的子类:
为抽象类:定会存在具体的子类,否则没有意义;
为具体类;他才有意义,才可以创建实例.
(4)抽象类的本质:
强制子类必须完成的事情!
抽象类的特点:不能实例化(不能创建对象)
成员特点:
成员变量:
既可以是变量,也可以是常量;
成员方法:
既可以是抽象方法也阔以是非抽象方法.
构造方法啊:
存在无参/有参:分层初始化
目的:对数据进行初始化.
abstract和那些关键字冲突:
private:被private修饰的方法只能在本类中访问,有一个abstract关键字;强制子类重写:
final:被final修饰的成员方法,不能被重写,而被abstract强制子类重写.
static:被static修饰符的特点:需要被类名访问,随类的加载而加载,而被abstract需要让子类重写这个方法.
修饰类 抽象类;
修饰方法:抽象方法; public abstract 返回值类型 方法名(形式参数列表);
通过对象名来访问
方法重写的注意事项:
子类继承父类: 重写方法的时候,访问权限不能更低,跟父类的权限保持一致.否则报错
3.一个类如果没有抽象方法,那么将这个类定义为抽象类有什么意义呢?
意义:
就是为了不让外界new对象:不能实例化 抽象类特点:不能实例化 (如何实例化,通过抽象类多态实例化:具体的子类)
这个类没有抽象方法,将它定义为抽象类:
举例:
后面的日历类Calendar(特殊的常用类之抽象类) 还有很多jdk提供的
里面会存在一些静态功能:返回值是它自己本身
public static Calendar getInstance()
4.多态
定义:现实世界事物描述:一个事物体现出的不同形态
前提条件:
(1)不许存在继承关系,如果没有继承,就没有多态
(2)必须存在方法重写,需要让子类完成自己的业务功能,需要将父类的某些功能进行重写.
成员访问特点:
格式 Fu fu=new Zi();
父类 对象名=new子类名(); "向上转型"(使用的是父类的东西)
成员变量
编译看左,运行看左;
成员方法:(非静态的)
看左,运行看右.
员方法:算不上方法重写,和类相关的,称为"类成员" 编译看左,运行看左;
着类的加载而加载,使用类名访问
构造方法:
因为存在继承关系,存在无参构造/有参构造,都需要先父类初始化,然后才是子类,分层初始化.
好处:
(1)提高代码的复用性;
(2)提高代码的扩展性;
弊端:
格式:Fu fu =new Zi();向上转型 ,使用的是父类的东西,不能访问子类特有的功能.
解决方案:
(1)直接创建具体的子类:子类 new子类;
(2)父类引用指向子类对象,能不能将父类的引用强转子类引用? 向下转型.
Fu fu =new Zi();
格式:
Zi zi =(Zi) fu;
5.接口
定义:描述事物本身之外的额外功能.义:描述事物本身之外的额外功能.
举例:
电脑上的USB接口----->插上不同设备,电脑可以完成不同的动作:数据传输,打字,玩游戏,....
格式:
关键字interface 接口名{}----接口的命名规则和类一样.
特点:
1)不能实例化
2)接口中的方法:只能是抽象方法,不能有方法体.
实现:
接口的子类-------子实现类(接口和实现类:实现关系 impplements);
注意事项:
1)接口的子类可能是抽象类,那么肯定会存在最具体的子类,否则没有意义.
2)具体类,就是通过接口多态进行实例化;
接口名的对象名 = new 子实现类名();
3)开发中,定义解接口之后,在定义子实现类的时候,名称后面都会在接口名的后面+lmpl;
6.形式参数问题:
方法的形式参数可以数据基本类型,实际参数需要传递当前具体的基本类型的数值即可.
方法的形式参数是引用类型:
类:
具体类:调用该方法,实际参数需要传递的是当前具体类对象.
举例: 参数是一个具体的类,学生类.
public class Test1 {
public static void main(String[] args) {
StudentDemo s=new StudentDemo();
s.methid(new Student());
}
}
class Student{
public void study(){
System.out.println("学生每天都需要起床去上课");
}
}
class StudentDemo{
public void methid(Student student){
student.study();
}
}
抽象类;调用该方法,实际参数需要传递的是当前这个抽象类的子类对象,抽象类多态完成.
举例:参数为一个抽象类 学生类,小明类继承学生类,通过子类对象,抽象类多态调用study方法.
public class Test1 {
public static void main(String[] args) {
StudentDemo s=new StudentDemo();
s.methid(new XiaoMing());
}
}
abstract class Student{
public void study(){
System.out.println("学生每天都需要起床去上课");
}
}
class XiaoMing extends Student{
public void study(){
System.out.println(" 小明每天都去太阳小学去学习 ");
}
}
class StudentDemo{
public void methid(Student student){
student.study();
}
}
接口:调用该方法,实际参数传递的是当前接口的子实现类对象,接口类多态.
举例:实际参数为接口Student.通过接口多态调用方法.
public class Test1 {
public static void main(String[] args) {
StudentDemo s=new StudentDemo();
s.methid(new XiaoMing());
}}
interface Student{
public void study();}
class XiaoMing implements Student{
public void study(){
System.out.println(" 小明每天都去太阳小学去学习 ");
}
}
class StudentDemo{
public void methid(Student student){
student.study();
}
}
7.instanceof:判断
对象名 instanceof 类名
判断当前对象名是否当前类的实例;
举例: 看程序,写结果.
class Animal{}
class Cat extends Animal{}
class Dog extends Animal{}
public class Test{
public static void main(String[] args){
Cat cat=new Cat();
Animal a=new Dog();
if(cat instanceof Cat){
System.out.println(" 猫会喵喵的叫");
}else if(a instanceof Dog){
System.out.println("狗会看门");
}
}
}
8.权限修饰符的范围
关系: 同包当前类 同包子类/无关类 不同包子类 不同包无关类
private Y
默认修饰符 Y Y
protected Y Y Y
public Y Y Y Y
四个权限修饰符的优先级:
从大到小为:
public protected 默认修饰符 private
9.返回值问题的研究
方法的返回值类型:
基本数据类型:简单:通过功能的业务操作,返回的数据结果
引用数据类型:
类;
具体类:如果一个方法的返回值是一个具体类,那么该方法就需要返回当前类的具体对象
举例: 返回一个Student类型.
public class Test1 {
public static void main(String[] args) {
StudentDemo s=new StudentDemo();
Student s1 = s.methid();
s1.study();
}}
class Student{
public void study(){
System.out.println( "学生们都需要学习");
}
}
class StudentDemo{
public Student methid(){
return new Student();
//Student s1=new Student();
// return s1;
}
}
抽象类:返回值类型是一个抽象类Student,通过创建子实现类,然后抽象类多态调用方法.
public class Test1 {
public static void main(String[] args) {
StudentDemo s=new StudentDemo();
Student methid = s.methid();
methid.study();
}}
abstract class Student{
public abstract void study();
}
class XiaoHong extends Student{
public void study(){
System.out.println(" 小红需要去东方幼儿园去学上课");
}
}
class StudentDemo{
public Student methid(){
//Student s=new XiaoHong();
// return s ;
return new XiaoHong();
}
}
接口:
举例:返回值类型一个接口,通过接口的子实现类,然后通过接口多态调用方法
public class Test1 {
public static void main(String[] args) {
StudentDemo s=new StudentDemo();
Student methid = s.methid();
methid.study();
}}
interface Student{
void study();
}
class XiaoHua implements Student{
public void study(){
System.out.println(" 小花需要去天鹅幼儿园去学上课");
}
}
class StudentDemo{
public Student methid(){
//Student s=new XiaoHong();
// return s;
return new XiaoHua();
}
}
10.带包的编译和运行
10.1同一个包下的编译和运行;
在同一包下:
首先:创建package包名(推荐多级包:中间点隔开,分包)
两种情况:
1)手动方式:
a)将你当前的多级包名创建出来
b)先将当前的Java文件进行编译
在当前目录中:使用javac java源文件 ---->.class文件
c)将当前字节码文件存储在刚才1)包下
d)带包进行运行
java 包名.类名
2)自动方式:
a)对Java文件进行编译
javac -d . 某个Java文件 ---->自动的产生包名和字节码文件
b)带包进行运行
java 包名.类名
10.2不同包下的编译和运行;
直接使用自动方式
1)将当前Demo类先进行编译
2)将Test类进行编译
pakcage和class中间:import 包名.类名;
它里面用到Demo类,需要导包,而且必须保证当前类的访问权限足够大
3)运行 com.qf.Test类
11.内部类
定义:在一个类A中定义另外一个类B,那么类B就是类A的内部类.
分类:
成员内部类:在一个类的成员位置定义的;
局部内部类:在一个类的成员方法中定义的;
可以访问外部类的成员,包含私有.
访问方式:
直接访问成员内部类的成员:
格式:外部类名.内部类名 对象名=外部类对象.内部类对象;
直接访问静态成员内部类的成员:
外部类名.内部类名 对象名=new 外部类名.内部类名();
匿名内部类: 应用场景1:
方法得形式参数是一个抽象类;
举例:
public class Marry {
public static void main(String[] args) {
ADemo ad=new ADemo();
ad.method(new A() {
@Override
public void show() {
System.out.println(" 结婚了 ");
}
});
}
}
abstract class A{
public abstract void show();
}
class ADemo{
public void method(A a){
a.show();
}
}
应用场景2:
方法的形式参数是一个接口类型;
匿名内部类的本质:继承了该抽象类或者实现了该接口的子类对象!
new 抽象类名/接口名(){
重写方法
} ;
举例:
public class Marry {
public static void main(String[] args) {
ADemo ad=new ADemo();
ad.method(new A() {
@Override
public void show() {
System.out.println(" 结婚了 ");
}
});
}
}
interface A{
void show();
}
class ADemo{
public void method(A a){
a.show();
}
}
匿名内部类的返回值问题:
方法的返回值是抽象类:
public class Marry {
public static void main(String[] args) {
ADemo ad=new ADemo();
A method = ad.method();
method.show();
}
}
abstract class A{
public abstract void show();
}
class ADemo{
public A method(){
return new A(){
@Override
public void show() {
System.out.println("结婚了...");
}};
}
}
方法的返回值是一个接口类型:
举例:
public class Marry {
public static void main(String[] args) {
ADemo ad=new ADemo();
A method = ad.method();
method.show();
}
}
interface A{
void show();
}
class ADemo{
public A method(){
return new A(){
@Override
public void show() {
System.out.println("结婚了...");
}};
}
}
12.Object类
1.Object类的getClas方法的目的是什么?
目的就是可以获取正在运行的类(Class):代表着就是字节码文件对象;
2.pulbic String toString():返回对象的字符串表示形式;
创建对象:输出对象名称,打印出来的对象的地址值,没有意义;
应该看到的是当前这个对象的成员信息表达式!
建议所有子类覆盖此方法;
3.public boolean equals(Object obj):指示其他对象与此对象是否"相等"
==和equals 的区别:
==:连接起来的基本数据,比较的基本数据类型数值是否相等;
==;连接起来的引用数据类型,比较的是引用数据类型的地址值是否相同;
equals:默认比较的是地址值是否相同,建议子类重写equalsa方法,比较他们内容是否相同
(成员信息是否相同);
在重写equals方法的同时,还需要重写hashCode()方法,保证哈希码值必须一样,这样才有比较equals,
4. protected Object clone() throws CloneNotSupportedException:调用过程中可能存在克隆不支持的异常.
对于jdk提供的类的方法本身存在异常,谁调用这个方法,必须做出处理,否则报错,最简单的方式继续往上抛throws.
创建并返回对象的副本(浅克隆)---------复制对象,获取对象的成员.
5.Scanner.java.util的类:文本扫描器-------录入数据;
构造方法; public Scanner (InoutStream source);
成员方法:
判断功能: haxNextXXX();判断下一个录入的是否否是XXX类型的;
获取功能: nextXXX();
例子:public int nextInt();
public String nextLine();
键盘录入的细节:
录入的字符串和int类型:
先录入int,再录入字符串:字符串会被漏掉
原因:"回车符号的问题",解决:
1)可以使用next()--------录入的也是字符串;
2)在录入String之前,在创造一个新的键盘录入对象:不叫耗费内存.
6.String类
String类代表字符串。
'Java程序中的所有字符串文字(例如"abc" )都被实现为此类的实例。 "字符串本身就是常量"
String的特点:
字符串不变的; 它们的值在创建后不能被更改
推荐方式:
String 变量名 = "字符串常量" ;
String,作为形式参数传递,有什么特点
String类型作为形式参数和基本类型作为形式的效果一样,
形式参数的改变不会直接影响实际参数,String类型特殊的引用类型!
其他引用数据类型,形式参数的改变会直接影响实际参数!
知道:构造方法有哪些
public String():无参构造
String(byte[] bytes):将字节数组可以构造字符串对象
public String(byte[] bytes,int offset,int length)一部分字节数组构造成字符串对象
public String(char[] value):将字符数组构造成字符串对象
public String(char[] value, int offset,int count):将一部分字符数组构造成字符串对象
public String(String original):创建一个字符串对象,里面存储字符串常量
String类的获取功能:
char charAt(int index) :获取指定索引出的字符值
public String concat(String str):拼接功能:拼接新的字符串
public int indexOf(int ch):返回指定字符第一次出现的字符串内的索引
int lastIndexOf(int ch) :查询指定字符最后一次出现的索引值
int length() :获取字符串长度
public String[] split(String regex):字符串的拆分方法:返回的字符串数组 (重要)
String substring(int beginIndex) :字符串截取功能 (重要)
默认从beginIndex起始索引截取到末尾
public String substring(int beginIndex,int endIndex) :从指定位置开始截取到指定位置结束(包前不包后)
包含beginIndex位置,不包含endIndex位置,包含到endIndex-1;
String类的转换功能:
public char[] toCharArray():将字符串转换字符数组
byte[] getBytes() :使用平台的默认字符集进行编码过程:将字符串--->字节数组
byte[] getBytes(String charset):使用指定的字符集进行编码 "GBK/UTF-8"
编码和解码
编码:将能看懂的字符串---->看不懂的字节
解码:将看不懂的字节----->能看懂的字符串
public String toLowerCase():将字符串中的每一个字符转换成小写
public String toUpperCase():将字符串中的每一个字符转换成大写
static String valueOf(boolean b/float/long/double/int/char /....Object)
String的判断功能
public boolean contains(String s):判断是否包含子字符串
public boolean startsWith(String prefix):判断是以指定的字符串开头
public boolean endsWith(String suffix):判断是是以指定的字符串结尾
boolean equals(Object anObject) :判断字符串内容是相等:区分大小写
boolean equalsIgnoreCase(String anotherString) :判断字符串内容是否相等,忽略大小写 public boolean isEmpty():判断字符串是否为空
万能方法:
将任意的数据类型转换成String :静态的功能
String substring(int start):从指定的位置截取到默认结束,返回的新的字符串.
String substring(int start,int end):从指定位置开始截取,到指定位置结束(抱歉不包后)
7.字符串的特点:
字符串是不变的;他们的值在创建后就不能更改了
字符串是常量:在内存中:方法区中的常量池中储存;
构造方法:
8.StringBuffer;
StingBuffer():无参构造方法,使用局多;
StringBuffer(int capacity):指定容量大小的字符串缓冲区;
StringBuffer(String str):指定缓冲区的具体内容str,容量大小=16个默认容量+当前字符串的长度.
public intlength():获取字符缓冲区的长度;
public int capacity():获取字符串缓冲区的容量大小;
添加新的字符序列:
StringBuffer append(任何数据类型):将任何数据类型的数据追加到字符序列中(字符缓冲区);
StringBuffer insert(int offset,String str):插入元素,在指定的位置插入指定的元素;
删除字符序列:
public StringBuffer deleteCharAt(intindex):在指定的位置删除的指定的字符,返回字符串缓冲本身;
public stringBuffer delete(int start,int end):删除指定的字符从指定位置开始,到end-1出结束.
反转功能
public StringBuffer reverse():反转功能,
9.应用;
例子1: 键盘录入一个字符串数据:
举例: 录入 "Helloworldjavaee"
输出结果:"hELLOWORLDJAVAEE"
将第一个字符转换成小写,后面字符开始----大写
分析:使用字符串的获取(截取功能)和转换
1)创建键盘录入对象
2)录入String数据
3)subString功能将第一个字符截取出来,----->新的字符串----->转换成小
写
4)将后面的字符的所有元素,截取出来---->新的字符串---->转换成大写
5)将3)+4)的结果拼接:concat()
public class Test {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in) ;
//提示并录入数据
System.out.println("请录入字符串数据:");
String line = sc.nextLine() ;
//截取第一个字符出来
String s1 = line.substring(0, 1);
//将s1字符串--->转换小写
String s2 = s1.toLowerCase();
//截取后面的子字符串出来
String s3 = line.substring(1);//默认截取到末尾
//将s3转换成大写
String s4 = s3.toUpperCase();
//将s2和s4拼接
String result = s2.concat(s4) ;
System.out.println("result:"+result);
System.out.println("----------------------------------------------------");
//链式编程
String result2 = line.substring(0, 1).toLowerCase().
concat(line.substring(1).toUpperCase());
System.out.println("result2:"+result2) ;
}
}