1.package
作用是将字节码文件.class分类存放
多级.分开,一个java文件只能有一句package语句
此时需要使用import进行导包
package,import,class是否有先后顺序?
先package,再import,最后是class
2.权限修饰符
private 仅可本类
默认 本类 同一包下
protected 本类 同一包下 不同包下的子类
public 本类 同一包下 不同包下的子类 不同包下的无关类
3.内部类
内部类就是在类内部创建的类
内部类访问的特点:
内部类随便访问外部类的成员
外部类访问内部类需要创建内部类对象
格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象(也就是new 外部类().new 内部类())
私有内部类的使用:
class Outer {
private int num = 60;
private class Inner {
public void method() {
System.out.println(num);
}
}
public void Rao() {
Inner inn = new Inner();
inn.method();
}
}
在外部类的内部提供一个创建私有内部类并调用对应方法的方法,直接新建外部类对象调用该方法即可。
静态内部类使用:
public class Practice {
public static void main(String[] args) {
Inner1 inner1 = new Outer.Inner1();
inner1.print1();
new Outer.Inner2().print2();
}
}
class Outer{
static class Inner1{
public void print1(){
System.out.println(666);
}
}
static class Inner2{
public static void print2(){
System.out.println(777);
}
}
}
静态可以直接使用,非静态必须创建对象。
成员内部类面试题:
public class Practice {
public static void main(String[] args) {
Inner inner = new Outer().new Inner();
inner.method();
}
}
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void method(){
int num =30;
System.out.println(?);
System.out.println(??);
System.out.println(???);
}
}
}
?,??,???位置分别填上对应代码,使之依次输出10,20,30.
System.out.println(Outer.this.num);
System.out.println(this.num);
System.out.println(num);
就近是30,this调用本类也就是内部类的是20,Outer.this调用外部类的变量。
局部内部类在访问它所在方法的局部变量一定要加final,为什么?
因为在调用这个方法的时候,如果局部变量没有用final修饰,那么局部变量的生命周期和方法的生命周期是一样的,当方法发生弹栈,它就随之消失。如果局部内部类还没有马上消失想要使用这个局部变量,也无法使用。如果使用final修饰,局部变量就会进入内存中方法区的常量池中,延长了局部变量的生命周期。
JDK1.8取消了该限制。
4. 匿名内部类
前提条件:存在一个接口或者一个类
格式:new 类名或者接口名(){
重写方法;
}.方法名;
本质:继承了该类或者实现了该接口的子类匿名对象。
匿名内部类重写多个方法调用:
public class Practice {
public static void main(String[] args) {
new Outer().method();
}
}
interface Inter {
public abstract void print1();
public abstract void print2();
}
class Outer {
public void method(){
new Inter(){
@Override
public void print1() {
System.out.println("1");
}
@Override
public void print2() {
System.out.println("2");
}
}.print1();
new Inter(){
@Override
public void print1() {
System.out.println("1");
}
@Override
public void print2() {
System.out.println("2");
}
}.print2();
}
}
调用多个方法每次都需要重新创建并且需要全部重写,明显很麻烦。改进方法如下:
class Outer {
public void method(){
Inter inter = new Inter(){
@Override
public void print1() {
System.out.println("1");
}
@Override
public void print2() {
System.out.println("2");
}
public void print3(){
System.out.println("3");
}
};
inter.print1();
inter.print2();
}
}
父类引用指向子类对象。但是该引用不能调用匿名内部类特有的方法,但是因为本身没有子类,只有子类对象,无法向下转型。所以,不建议使用!一般匿名内部类只在调用一次方法的时候使用。
匿名内部类在开发中的使用
当做参数传递,类似于匿名对象,不同的是他是作为类或者接口的子类传入,并且需要重写方法。
多线程和监视器的时候常用。
实际代码如下:
public class Practice {
public static void main(String[] args) {
PersonDemo pd = new PersonDemo();
pd.method(new Person(){
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("匿名内部类的实际开发");
}
});
}
}
abstract class Person{
public abstract void show();
}
class PersonDemo{
public void method(Person p){
p.show();
}
}
匿名内部类的面试题:
//在*位置填入适当代码,使程序顺利运行且最后的显示结果为HelloWorld
public class Practice {
public static void main(String[] args) {
Outer.method().show();
}
}
interface Inter {
void show();
}
class Outer{
*
}
分析:
因为method直接调用,所以该方法为static的,并且方法名为method。
因为可以调用show,所以该方法返回值一定是Inter对象或者Inter的子类。因为接口不能被实例化,所以是Inter子类,因为没有自雷,所以一定是匿名内部类,在类的内部重写show方法,使之为HelloWorld的输出语句。
所以在*中的代码为:
public static Inter method(){
return new Inter(){
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("HelloWorld");
}
};
}
5.eclipse的使用
不同项目交互:打jar包,jar包放进lib文件夹,方便管理,添加进classpath(build path)。
删除勾选从磁盘删除,不勾选只删除项目。
所有和视图有关的都在window里面,视图混乱可以使用
6.Object类
hashcode,getClass,toString,equals
hashcode查看不同对象是否一样
getclass同时了解返回类型的其他方法
toString源码源码组成及重写(直接打印对象的引用,默认调用toString方法)
equals源码组成及重写(默认比较地址没实际意义,自己写的注重属性的比较)
==和equals方法的区别
共同点:返回值都是boolean类型,都可以用于比较
不同点:==是运算符,既可以比较基本数据类型,也可以比较引用数据类型。基本数据类型比较的是值,引用数据类型比较的是地址。
equals只能比较引用数据类型,因为它是方法,只有对象可以调用,但是因为它比较的是引用对象的地址值,没有实际意义,所以我们一般重写该方法。
7.Scanner类
public static final InputStream in; 标准的输入流,对应着键盘录入。
int | nextInt() 将输入信息的下一个标记扫描为一个 int。 |
构造成功后调用上述方法,如果输入的不是对应类型的值,报错如下:
Exception in thread "main" java.util.InputMismatchException
查询对应API,发现是类型不匹配导致的问题。解决方法就是调用这个方法:
boolean | hasNextInt() 如果通过使用 nextInt() 方法,此扫描器输入信息中的下一个标记可以解释为默认基数中的一个 int 值,则返回 true。 |
通过加入判断,如果是该类型再调用nextInt方法,不是输出提示语句。
nextInt和nextLine方法分别获取两次可以正常运行,但是先获取int再获取line就会出错,为什么呢?
int后自带/r /n,而nextLine就是一次为界限的,通过读取nextInt的/r /n,他就认为已经完成了输入,所以nextLine获取不到对应的值。
8.String类
String
类代表字符串。Java 程序中的所有字符串字面值(如 "abc"
)都作为此类的实例实现。
需要注意的是字符串是常量,一旦被赋值就无法改变
String类的构造方法
String() 初始化一个新创建的 String 对象,使其表示一个空字符序列。 |
String(byte[] bytes) 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String 。 |
String(byte[] bytes, int offset, int length)
通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String
。
无参构造的String类中是空的。
有参可以使用byte,char等数组进行构造,offset是偏移量,表示开始的索引,length表示要构造的长度。
面试题五则:
public static void main(String[] args) {
//demo1();
//demo2();
//demo3();
//demo4();
String s1 = "ab";
String s2 = "abc";
String s3 = s1 + "c";
System.out.println(s3 == s2); //false
System.out.println(s3.equals(s2)); //true
}
private static void demo4() {
//byte b = 3 + 4; //在编译时就变成7,把7赋值给b,常量优化机制
String s1 = "a" + "b" + "c";
String s2 = "abc";
System.out.println(s1 == s2); //true,java中有常量优化机制
System.out.println(s1.equals(s2)); //true
}
private static void demo3() {
String s1 = new String("abc"); //记录的是堆内存对象的地址值
String s2 = "abc"; //记录的是常量池中的地址值
System.out.println(s1 == s2); //false
System.out.println(s1.equals(s2)); //true
}
private static void demo2() {
//创建几个对象
//创建两个对象,一个在常量池中,一个在堆内存中
String s1 = new String("abc");
System.out.println(s1);
}
private static void demo1() { //常量池中没有这个字符串对象,就创建一个,如果有直接用即可
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2); //true
System.out.println(s1.equals(s2)); //true
}
最后一个面试题参考资料JDK的api中String描述:
Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder
(或 StringBuffer
)类及其 append
方法实现的。字符串转换是通过 toString
方法实现的,该方法由 Object
类定义,并可被 Java 中的所有类继承。(相当于创建了一个StringBuffer接收数值,再调用toString方法转化为String)下面是上述案例的内存图:
9.String类的判断功能
* boolean equals(Object obj):比较字符串的内容是否相同,区分大小写
* boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写
* boolean contains(String str):判断大字符串中是否包含小字符串
* boolean startsWith(String str):判断字符串是否以某个指定的字符串开头
* boolean endsWith(String str):判断字符串是否以某个指定的字符串结尾
* boolean isEmpty():判断字符串是否为空。
值得注意的是isEmpty方法。如果String = ""为空字符串,如果String =null则会报错:
Exception in thread "main" java.lang.NullPointerException
null和""的区别:
""是字符串常量,也就是String类的对象,所以可以调用方法。
null是空常量,不能调用任何方法,否则会报空指针异常。
模拟登陆小程序
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
for (int i = 0; i < 3; i++) {
System.out.println("请输入用户名:");
String username = sc.nextLine();
System.out.println("请输入密码:");
String password = sc.nextLine();
if("shuaige".equals(username) && "shiwo".equals(password)){
System.out.println("登陆成功");
break;
}else{
if(i==2){
System.out.println("今天次数用完了,请明天再来哦~");
}else{
System.out.println("用户名或密码错误,请重新输入。你今天还有"+(2-i)+"次机会!");
}
}
}
}
很简单,需要注意的是,在应用中,涉及到判断的时候,尽量用常量字符串调用变量字符串,这样可以防止出现空指针的错误。
10.String的获取功能
int length():获取字符串的长度。不同于数组,数组的length是属性,String的length是方法,数组的length后面没有()。
char charAt(int index):获取指定索引位置的字符
int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引。
int indexOf(String str):返回指定字符串在此字符串中第一次出现处的索引。
int indexOf(int ch,int fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引。
int indexOf(String str,int fromIndex):返回指定字符串在此字符串中从指定位置后第一次出现处的索引。
lastIndexOf:从后向前查,但是索引不变。
String substring(int start):从指定位置开始截取字符串,默认到末尾。(左闭右开,含头不含尾)
String substring(int start,int end):从指定位置开始到指定位置结束截取字符串。
String s = "zheshixianjing";
String s1 = s.substring(6, 10);
System.out.println(s);
System.out.println(s1);
这段代码可以发映出substring的两个特点,一个是substring包含头不包含尾,另一个就是substring是产生了一个新的字符串,不会对原字符串造成影响。
面试题:统计不同类型的字符出现的次数:
public static void main(String[] args) {
String s = "dsuafhqfeAGYBHJBHGF12349>";
int small = 0;
int big = 0;
int number = 0;
int other = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) >= 'a' && s.charAt(i) <= 'z') {
small++;
} else if (s.charAt(i) >= 'A' && s.charAt(i) <= 'Z') {
big++;
} else if (s.charAt(i) >= '1' && s.charAt(i) <= '9') {
number++;
} else {
other++;
}
}
System.out.println("小写字母有" + small + "个,大写字母有" + big + "个,数字有" + number + "个,其他字符有" + other + "个。");
}
11.String类的转换功能
byte[] getBytes():把字符串转换为字节数组。
char[] toCharArray():把字符串转换为字符数组。
static String valueOf(char[] chs):把字符数组转成字符串。
static String valueOf(int i):把int类型的数据转成字符串。
注意:String类的valueOf方法可以把任意类型的数据转成字符串。
String toLowerCase():把字符串转成小写。(了解)
String toUpperCase():把字符串转成大写。
String concat(String str):把字符串拼接。
到这里,统计字符串中不同字符就有了两种方法,一种是先遍历,在对应位置进行charAt获取当前索引位置的值,另一种是直接调用getBytes先把字符串转化为字符数组,然后再遍历。
concat的拼接和String+String效果一样,但是实际上+功能更为强大。
两个小Demo。分别是按标准格式转换成首字母大写的字符串,使用了链式编程。和把数组按照字符串的格式输出。
public static void demo2() {
int[] arr = {1,2,3,4};
String f = "[";
System.out.print(f);
for (int i = 0; i < arr.length; i++) {
if(i==arr.length-1){
System.out.print(arr[i]+"]");
}else{
System.out.print(arr[i]+",");
}
}
}
public static void demo1() {
String s = "BiaozzGGnsugwuHD";
String substring = s.substring(0, 1).toUpperCase().concat(s.substring(1).toLowerCase());
System.out.println(substring);
}
12.String类的其他功能
A: String的替换功能及案例演示
String replace(char old,char new)
String replace(String old,String new)
B: String的去除字符串两空格及案例演示
String trim()
C: String的按字典顺序比较两个字符串及案例演示
int compareTo(String str)(暂时不用掌握)
int compareToIgnoreCase(String str)(了解)
trim方法只去两边的空格。
13.String类API的综合使用案例
public class Practice1 {
/*
* 键盘录入字符串,然后反转
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入你想要转换的字符串:");
String nextLine = sc.nextLine();
char[] array = nextLine.toCharArray();
String s = "";
for (int i = array.length - 1; i >= 0; i--) {
s = s + array[i];
}
System.out.println(s);
}
}
public class Practice2 {
/*
* 在大串中查找小串出现的次数
*/
public static void main(String[] args) {
String da = "woaishenghuo,shenghuohenmeihao,shenghuohenyouqu";
String xiao = "shenghuo";
//设定索引值
int index = 0;
//设定计数器
int count = 0;
while ((index = da.indexOf(xiao)) != -1) {
count++;
//设定继续查找的长字符串
da = da.substring(index + xiao.length());
}
System.out.println(count);
}
}
思路:找到就去掉前面部分,在剩余的里面继续找。