- io流 inputstream和outputstream相关的概念和用法 字节流和字符流
- 可以理解为四个基类 reader/writer input/output
- reader是字符,input是字节
- 那么什么是字符(character)和字节(byte)呢?
- 首先可以如果联想到Java中一个char是两个字节,猜测inpustream一次读一个字节,reader读两个字节?(这样不完全对)
- 举个反例 比如“我们学习JAVA”是八个字符,十二个字节,所以不能统一除以二理解~因为中美开花()
- 在适用范围上有什么区别呢?
- 字节流是everything can use
- 字符流是only control char or string
- reader writer是基类
- inputstream reader是字节 stream 到字符 stream的bridge(是装饰模式里面的次要特征)
- 八大基本数据类型 是那几个 存储方案 各自有什么特征
- byte(1),short(2),int-Interger(4),long(8)
float(4),double(8)
boolean(true&false),char-character(2) - 这些类型的定义是通过诸如int a = 3;long b = 255L;的形式来定义的。基础变量类型不存在引用的说法,引用只限于String和自定义对象这样的非基础变量类型,int a = 1 装的不是地址,而是0x00000001这个值本身,不是间接寻址,且由于大小可知,生存周期可知(这些字面值定义在某个程序块里面,程序块退出后,字段值就消失了),出于一些原因,就存在于栈中。
- 栈里不同帧的变量不能共享,同一帧的变量可以共享,比如函数a里面有个int i,在函数b里面就不能用到这个i,只有a这个函数内部才能用到,因为同处一个栈帧。
- 但是如果你在对象内部初始化了一个成员变量,那就会存在堆内的该对象里!所以不是all basic variable put in stack!
- 请注意一个方法内的基本数据类型依旧存在stack里面!
- JVM里有常量池存在方法区,8种基本数据类型的包装类,除了Float和Double都可以使用常量池,String也可以。如果是Integer a = 3; Integer b = 3 ,这样a和b是指向常量池(有大小限制)中同一块空间,继续执行Integer a = 4,则会在常量池中开辟空间存放4,然后a指向该空间。如果静态变量 int a = 4,是放在堆里,在方法中的局部变量 int a = 4,是在栈里。
- 如下面这个代码
- byte(1),short(2),int-Interger(4),long(8)
public class Person {
int age = 10;
void call() {
int m = 100;
System.out.println("in heap m is "+m);
}
public static void main(String[] args) {
int m=10;
System.out.println("in stack is "+m);
Person p1 = new Person();
System.out.println("in heap age is "+p1.age);
p1.call();
}
}
-
- 下图是上面代码的内存解析!
- 下图是上面代码的内存解析!
-
java程序的入口形式 main函数
- main方法的形式是固定的,以下写法都不能作为程序的入口:
public static void mian()//必须带String[]参数
public static int main(String[] args)//返回值必须为void
public void main(String[] args) //必须是static
但是如果只是修改String[]的名字那是可以的~
public void main(String[] argsssssssss) // args其实就是一个正常的数组名字编译器不会在乎这个string数组叫啥名字,所以叫啥都行,只是为了符合数组形参的写法规定 - 方法签名讲解
public:该修饰符表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用。
static:该修饰符表示静态的意思,简单理解被static修饰符修饰的成员都属于类本身,而不属于类的某个实例,静态成员不能能直接访问非静态成员。
void:使用void说明没有返回值。 - 使用这些方法签名的原因: (使用这些修饰符理解static就好了,其他的说法不太严谨,static就是为了在初始化对象之前可以调用,考试的时候说是规定就好了)
public修饰符:java类由JVM启用,为了没有限制可以自由的调用,所以采用public修饰符。
static修饰符:JVM启用这个main方法时肯定不是先创建这个main方法的主类的对象,再通过对象来调用方法,而是直接通过该类来调用这个方法,因此需要使用static修饰符修饰这个类。
void返回值:main方法被JVM启用,将返回值返回给JVM没有任何意义,因此该方法没有返回值,所以使用void。 - 这时会发现我没有说字符串数组形参内容,这里我们首先知道,谁调用方法,谁去传递形参
不难通过上面分析看到args形参由参数是程序员通过命令行赋值的,一般情况下你在ide里面运行的时候,点击编译运行就好
如下:
- main方法的形式是固定的,以下写法都不能作为程序的入口:
public class args {
public static void main(String[] args){
for (String s:args) {
System.out.println(s);
}
System.out.println("-------------------" );
System.out.println(args.length);
}
}
输出:
0
这里输出数组长度为0,这是因为,程序没有给args设定参数值,所以JVM也就不知道args数组中的元素,然后JVM给args数组设置为一个长度为0的数组。
如果我们使用dos命令运行程序时,在类名后加上一个或者多个字符串(以空格隔开),这时JVM会依次将这些数值赋给args数组。 例如:
javac myFile.java
javac表示java compiler,这一步执行完之后编译出了myFile.class
下一步: java myFile. class 1 2 3 4 5 a b 6
这一步就是运行,后面跟着的数字会传到args数组里面,所以你程序main里实际上里面是可以用,args[0],args[1]这些参数的,取决于你到底传了几个,所以如果你只传了1个,却用了args[2],就会报数组越界异常
输出:
7
-
java监视器 action event类型的事件 监视器的方法
- 三个概念:事件源, 监视器, 处理事件的接口
- 事件源
能够产生事件的对象都可以成为事件源,如文本框、按钮、下拉式列表等。 事件源必须是一个对象,而且这个对象必须是
Java认为能够发生事件的对象。 - 监视器
一个对事件源进行监视,以便对发生的事件做出处理的对象。 事件源通过调用相应的方法将某个对象作为自己的监视器,例如。
对于文本框,这个方法是
addActionListener(监视器);
对于获取了监视器的文本框对象,在文本框获得输入焦点之后,如果用户按回车键,Java运行系统就自动用ActionEvent类创建
一个对象, 即发生了ActionEvent事件。 也就是是说,事件源获得监视器之后,相应的操作就会导致事件的发生,并通知监视器,
监视器就会做出相应的处理。 - 处理事件的接口
监视器负责处理事件源发生的事件。 监视器是一个对象,为了处理事件源发生的事件,监视器这个对象会自动调用一个方法来
处理事件。
Java规定:为了让监视器这个对象能够对事件源发生的事件进行处理,创建该监视器对象的类必须声明实现相应的接口,即必须
在类体中给出该类接口中所有方法的方法体,那么当事件源发生事件时, 监视器就自动调用执行被类实现的某个接口方法。
java.awt.event包中提供了许多事件类和处理各事件的接口。对于文本框这个接口的名字是ActionListener,这个接口中只有一
个方法:
public void actionPerformed(ActionEvent e); - 总结:
其过程可以总结为:通过实现某个接口来定义一个监视器类,在这个类中给出该接口中所有方法的方法体;为某一事件源(文本框等)
-
Chain-责任链
- 简单理解成击鼓传花, 即多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条线,并沿着这条链传递该请求,直至有对象处理它为止。
- 如图 责任链的核心在“链”,由“链”上所有的成员去处理请求并返回结果。 类图中各个角色定义如下:
Client:客户端向发起请求,责任链对客户端透明
Handler:责任链抽象类,负责定义处理逻辑以及组装责任链机制
ConcreteHandler:责任链中的链由多个ConcreteHandler组装而成
-
char类型的特点 存储字节多少个(这里老师发音不标准 不知道是不是char)
- char是Java中的保留字,与别的语言不同的是,char在Java中是16位的,因为Java用的是Unicode
- char运算
char类型是可以运算的因为char在ASCII等字符编码表中有对应的数值。
在Java中,对char类型字符运行时,直接当做ASCII表对应的整数来对待。
char m = ‘a’ + 1;//输出结果是b。//提升为int,计算结果’a’ = 97 + 1 = 98 对应的字符是’b’ - 在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情况。
为了解决这个问题,Java语言为内置数据类型char提供了包装类Character类。
Character类提供了一系列方法来操纵字符。你可以使用Character的构造方法创建一个Character类对象,例如:
Character ch = new Character(‘a’);
在某些情况下,Java编译器会自动创建一个Character对象。
例如,将一个char类型的参数传递给需要一个Character类型参数的方法时,那么编译器会自动地将char类型参数转换为Character对象。 这种特征称为装箱,反过来称为拆箱。
-
ascii码的转换
- 举几个例子
0~9:
a~f:
- java中如何将一个字bai符转换为ascii码:
方法1:
char c = 'a ';
byte b =(byte)c;//byte刚好两个字节
方法2:
直接将这个字符转化为int型就可以得到ascii码值
char c = 'a ';
int b = c; //字符的ascii码值 - 同理将一个ascii码转换为相应的字符:
例如:字符a
int d = 97;
char e = (char)d;
- 举几个例子
-
程序中如何区分同名的局部变量和成员变量(全局变量
成员变量(全局变量) 和局部变量的区别- 在同一个方法中不能有同名的局部变量
- 局部变量不能有权限修饰符
- 局部变量必须赋值以后才能使用,成员变量可以不赋值
- 成员变量如果不赋值 系统会自动为其赋值 byte,short,int ,long =0 ,folat,double=0.0 ,boolean=false;
特别地,引用类型 = null; - 成员变量的作用域:不考虑权限修饰符是,一般作用于本类中
- 局部变量的作用域:只能作用于本方法中或者代码块中
- 所有变量必须先声明(定义)再使用。
- 下面的例子比较繁琐!对付考试记住这9和10两句话
- ** 函数总是临时性的东西,因为进栈它里面的东西就有效,出栈里面的东西就全没了**
- 方法里用的是局部变量,定义在类里面的是成员变量
- 举例:
首先我定义了一个Person类
然后在主函数里面创建对象并输出
输出结果是什么?并不是我们想象的我的年龄是20,而是下面这样:
想一下其实就很容易理解。
如果不同名,那么方法内的变量名代表成员变量;如果同名,那么方法内的变量名就只表示局部变量了,和成员变量一毛钱关系都没有了。
所以,首先当我们创建了一个Person对象p,在创建对象的时候就已经完成了成员变量的初始化了。成员变量age的初始值是1000。
当我们p.setAge(20)的时候,其实这个20只在setAge这个方法内起作用,所以输出了方法内年龄20,执行完这句话后,20就被销毁了。
然后执行sayHello,它里面的age代表的是成员变量的值,所以依旧是1000。
到这里如果还是不能理解,可以自己写代码看输出结果体会下。
那么,当同名的时候,我们就是要让这个变量名表示成员变量,有没有办法呢?
那就要说到this关键字了。我们把Person类改成这样:
再运行代码,发现代码运行结果变成了下面这样:
this表示的是当前对象。
this.age在这里具体表示p对象的age(即p对象的成员变量age)的值是20。
尽管两者的本质都是变量,可是使用时却有相当大的区别
先记住:在一个类中,如果一个变量能够用来描述一个类的属性,那就定义为成员变量,否则,它就应该定义为局部变量
-
异常处理的语法
- 在编写代码处理异常时,对于检查异常,有 2 种不同的处理方式:使用 try…catch…finally 语句块处理它。或者,在函数签名中使用 throws 声明交给函数调用者 caller 去解决
- try 块中的局部变量和 catch 块中的局部变量(包括异常变量),以及 finally 中的局部变量,他们之间不可共享使用。
每一个 catch 块用于处理一个异常。异常匹配是按照 catch 块的顺序从上往下寻找的,只有第一个匹配的 catch 会得到执行。匹配时,不仅运行精确匹配,也支持父类匹配,因此,如果同一个 try 块下的多个 catch 异常类型有父子关系,应该将子类异常放在前面,父类异常放在后面,这样保证每个 catch 块都有存在的意义。
java 中,异常处理的任务就是将执行控制流从异常发生的地方转移到能够处理这种异常的地方去。也就是说:当一个函数的某条语句发生异常时,这条语句的后面的语句不会再执行,它失去了焦点。执行流跳转到最近的匹配的异常处理 catch 代码块去执行,异常被处理完后,执行流会接着在 “处理了这个异常的 catch 代码块” 后面接着执行。而try块中的异常后面的代码就不会在执行。
有的编程语言当异常被处理后,控制流会恢复到异常抛出点接着执行,这种策略叫做:恢复式异常处理模式
而 Java 则是让执行流恢复到处理了异常的 catch 块后接着执行,这种策略叫做:终结式异常处理模式 - 不管有没有异常,finally中的代码都会执行
当try、catch中有return时,finally中的代码依然会继续执行
finally是在return后面的表达式运算之后执行的,此时并没有返回运算之后的值,而是把值保存起来,不管finally对该值做任何的改变,返回的值都不会改变,依然返回保存起来的值。也就是说方法的返回值是在finally运算之前就确定了的。 - 关于return的问题
finally代码中最好不要包含return,程序会提前退出,也就是说返回的值不是try或catch中的值
当try、catch中有return时,finally中的代码依然会继续执行
finally是在return后面的表达式运算之后执行的,此时并没有返回运算之后的值,而是把值保存起来,不管finally对该值做任何的改变,返回的值都不会改变,依然返回保存起来的值。也就是说方法的返回值是在finally运算之前就确定了的 -
类变量的修饰符
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
- 斜体表示考试应该不会考
- 类修饰符:
public(访问控制符),将一个类声明为公共类,他可以被任何对象访问,一个程序的主类必须是公共类。
abstract,将一个类声明为抽象类,没有实现的方法,需要子类提供方法实现。
final,将一个类生命为最终(即非继承类),表示他不能被其他类继承。
friendly,默认的修饰符,只有在相同包中的对象才能使用这样的类。
-
字符串的比较方法 现成的标准化的方法 不是数据结构里的
- == 比较的是地址,第一个排除
- equals是字符串内容相同时才会是true
- equalsIgnoreCase是忽略大小写,进行内容比较
-
几种常用类的常用方式 math类 date类
- Math 类位于 java.lang 包中,包含用于执行基本数学运算的方法, Math 类的所有方法都是静态方法,所以使用该类中的方法时,可以直接使用类名.方法名,如: Math.round();
- data类:
-
重写的含义
- 在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
- 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
- 重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
- 下面这一点考试不考 看看就行
- 重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,只能抛出 IOException 的子类异常。
在java多态机制中,对象在编译时期是属于父类类型,但是在运行时属于子类类型
也就是说在编译的时候,编译器发现catch中的IOException完全能将父类方法中抛出的异常捕获,因此编译通过,但是在运 行时期,由于对象变成了子类类型,子类重写的方法抛出的异常是Exception,显然IOException不能捕获这个比它更大的异 常,因此在运行时期也就出现失败。
总结:这个示例也就演示了一个道理,在java中,子类重写父类的方法时,子类如果选择抛出异常,那么抛出的异常类型不能大于父类的异常类型
-
不同修饰符的含义 final static之类
- 成员变量修饰符:
public(公共访问控制符),指定该变量为公共的,他可以被任何对象的方法访问。
private(私有访问控制符)指定该变量只允许自己的类的方法访问,其他任何类(包括子类)中的方法均不能访问。
protected(保护访问控制符)指定该变量可以别被自己的类和子类访问。在子类中可以覆盖此变量。
friendly ,在同一个包中的类可以访问,其他包中的类不能访问。
final,最终修饰符,指定此变量的值不能变。
static(静态修饰符)指定变量被所有对象共享,即所有实例都可以使用该变量。变量属于这个类。
transient(过度修饰符)指定该变量是系统保留,暂无特别作用的临时性变量。
volatile(易失修饰符)指定该变量可以同时被几个线程控制和修改。 - 方法修饰符:
public(公共控制符)对所有类可视
private(私有控制符)指定此方法只能有自己类等方法访问,其他的类不能访问(包括子类)
protected(保护访问控制符)指定该方法可以被它的类和子类进行访问。
final,指定该方法不能被重载。
static,指定不需要实例化就可以激活的一个方法。
synchronize,同步修饰符,在多个线程中,该修饰符用于在运行前,对他所属的方法加锁,以防止其他线程的访问,运行结束后解锁。
native,本地修饰符。指定此方法的方法体是用其他语言在程序外部编写的。
- 成员变量修饰符:
-
java里实现线程的途径
-
方式一:继承Thread类的方式
创建一个继承于Thread类的子类
重写Thread类中的run():将此线程要执行的操作声明在run()
创建Thread的子类的对象
调用此对象的start():①启动线程 ②调用当前线程的run()方法 -
方式二:实现Runnable接口的方式
创建一个实现Runnable接口的类
实现Runnable接口中的抽象方法:run():将创建的线程要执行的操作声明在此方法中
创建Runnable接口实现类的对象
将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
调用Thread类中的start():① 启动线程 ② 调用线程的run() —>调用Runnable接口实现类的run() -
方式三:实现Callable接口
说明:
与使用Runnable相比, Callable功能更强大些
实现的call()方法相比run()方法,可以返回值
方法可以抛出异常
支持泛型的返回值
需要借助FutureTask类,比如获取返回结果
Future接口可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等。
FutureTask是Futrue接口的唯一的实现类
FutureTask 同时实现了Runnable, Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值 -
方式四:使用线程池
说明:
提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
好处:
提高响应速度(减少了创建新线程的时间)
降低资源消耗(重复利用线程池中线程,不需要每次都创建)
便于线程管理 -
给出实现
-
//方式一
class ThreadTest extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
// 方式二
class RunnableTest implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
// 方式三
class CallableTest implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
sum += i;
}
return sum;
}
}
// 方式四
class ThreadPool implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
class Test {
public static void main(String[] args) {
// 继承Thread
ThreadTest thread = new ThreadTest();
thread.setName("方式一");
thread.start();
// 实现Runnable
RunnableTest runnableTest = new RunnableTest();
Thread thread2 = new Thread(runnableTest, "方式二");
thread2.start();
// 实现Callable<> 有返回值
CallableTest callableTest = new CallableTest();
FutureTask<Integer> futureTask = new FutureTask<>(callableTest);
new Thread(futureTask, "方式三").start();
// 返回值
try {
Integer integer = futureTask.get();
System.out.println("返回值(sum):" + integer);
} catch (Exception e) {
e.printStackTrace();
}
// 线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
ThreadPoolExecutor executor = (ThreadPoolExecutor) pool;
/*
* 可以做一些操作:
* corePoolSize:核心池的大小
* maximumPoolSize:最大线程数
* keepAliveTime:线程没任务时最多保持多长时间后会终止
*/
executor.setCorePoolSize(5);
// 开启线程
executor.execute(new ThreadPool());
executor.execute(new ThreadPool());
executor.execute(new ThreadPool());
executor.execute(new ThreadPool());
}
}
- 异常处理里 throw throws的区别
-
区别
throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。而throw则是指抛出的一个具体的异常类型。
throw和throws的区别主要有两点!
①、throw 后面跟的是对象,throws后面跟的是异常类
②、throw 定义函数体的内部,throws定义在函数名后。 -
throws:用于声明异常,例如,如果一个方法里面不想有任何的异常处理,则在没有任何代码进行异常处理的时候,必须对这个方法进行声明有可能产生的所有异常(其实就是,不想自己处理,那就交给别人吧,告诉别人我会出现什么异常,报自己的错,让别人处理去吧)。
格式是:方法名(参数)throws 异常类1,异常类2,… -
throw:就是自己进行异常处理,处理的时候有两种方式,要么自己捕获异常(也就是try catch进行捕捉),要么声明抛出一个异常(就是throws 异常~~)。
注意:
throw一旦进入被执行,程序立即会转入异常处理阶段,后面的语句就不再执行,而且所在的方法不再返回有意义的值! -
例子
-
class Demo {
public void getValue(int a, int b) throws MyException {
if (b < 0)
// 抛出异常对象
throw new MyException("除数不能为零!");
}
}
// 自定义异常要继承Exception 类
class MyException extends Exception {
public MyException(String message){
super(message)
}
}
class MainTest {
public static void main(String[] args) {
try {
Demo demo = new Demo();
demo.getValue(3, -1);
} catch (MyException e) {
e.printStackTrace();
}
}
}
- 界面编程 GridLayout使用方式
-
布局管理器之GridLayout(网格布局)
-
网格布局特点:
使容器中的各组件呈M行×N列的网格状分布。
网格每列宽度相同,等于容器的宽度除以网格的列数。
网格每行高度相同,等于容器的高度除以网格的行数。
各组件的排列方式为:从上到下,从左到右。
组件放入容器的次序决定了它在容器中的位置。
容器大小改变时,组件的相对位置不变,大小会改变。
设置网格布局行数和列数时,行数或者列数可以有一个为零。若rows为0,cols为3,则列数固定为3,行数不限,每行只能放3个控件或容器。若cols为0,rows为3,则行数固定为3,列数不限。
若组件数超过网格设定的个数,则布局管理器会自动增加网格个数,原则是保持行数不变。 -
例子
-
public class ShowGridLayout extends JFrame {
public ShowGridLayout() {
Container container=getContentPane();
//定义容器
container.setLayout(new GridLayout(4,3,10,20));
//创建具有指定行数、列数、组件水平、纵向一定间距的网格布局。
for(int i=1;i<=10;i++) {
container.add(new JButton("Component"+i));
}
}
public static void main(String[] args) {
ShowGridLayout frame=new ShowGridLayout();
frame.setTitle("show FlowLayout");
frame.setSize(200,200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
-
构造方法的调用特点
-
构造方法名必须与类名相同。
-
构造方法没有返回类型,但不用void声明(不用声明类型)。
-
可以指定参数及实现重载。
-
当实例化一个对象时,会自动调用构造方法。
-
一个类可以定义多个构造方法。
-
在机械语言里面会这样运行–>首先把this放到栈顶(aload_0),其次如果是子类会调用父类的构造函数
-
逻辑上构造一个子类对象,首先要构造一个父类对象,子类对象相当于套了一个父类对象,在它的基础上加上子类专有的东西。那么如果父类重写了构造函数,就是有一些自定义的初始化操作,比如传参数,这些编译器是没办法自动完成的
所以要人手动调用,来帮助父类对象初始化,只有父类对象初始化了,子类对象才能在它的基础上初始化,这也是为什么super要写在子类构造函数第一行。
-
-
接口/含有接口程序的特点
-
接口与类相似点:
一个接口可以有多个方法。
接口文件保存在 .java 结尾的文件中,文件名使用接口名。
接口的字节码文件保存在 .class 结尾的文件中。
接口相应的字节码文件必须在与包名称相匹配的目录结构中。 -
接口与类的区别:
接口不能用于实例化对象。//不能new
接口没有构造方法。//不能Constructor
接口中所有的方法必须是抽象方法。//例如void eat();
接口不能包含成员变量,除了 static 和 final 变量。
接口不是被类继承了,而是要被类实现。
接口支持多继承。 -
接口特性
接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错
public abstract void mathEar(); // 默认 -
抽象类和接口的区别
抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
接口中不能含有静态代码块以及静态方法( 不能用static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
一个类只能继承一个抽象类,而一个类却可以实现多个接口。
成员变量:
抽象类可有成员变量,也可以有常量
接口只能有常量(因为他无法给成员赋值,只能一开始就初始化)
成员方法:
抽象类可有抽象方法,也可有非抽象方法
接口只能有抽象方法,而且方法有默认修饰符public abstract
构造方法:
抽象类有构造方法
接口没有构造方法 -
为什么继承是单继承,而接口可以多实现
因为如果要继承的两个类中有同名方法,但方法实现不同,难以分清楚要继承的是哪个方法;但是对于接口来说,都只是给出方法定义,即使有同名方法,只要实现一次就可以。
-
-
对象的比较 两个对象是不是一个对象?
-
= =运算符的使用
"=="运算符用来比较两个变量是否相等,也就是说,这个运算符用于比较变量对应内存中所储存的数值是否相同,要比较两个基本类型的数据或两个引用变量是否否相等,只能使用 等等号运算符。
如果一个引用指向的数据是对象(引用类型),使用等等号运算符比较的是两个变量是否指向同一对象,也就是要看这两个对象是否在同一块储存空间,如果是要比这两个对象的内容是否相等,用此符号则无法实现。 -
equals方法的使用
equals方法是Object类提供的方法,每一个Java类都继承自Object类,所以每一个对象都具一个equals方法,Object类中定义的equals方法是直接使用"=="运算符比较两个对象,所以在没有覆写equals方法的情况下。equals与等等号的效果一样,比较的是引用。若想比较对象中的内容,需要覆写equals方法。
因为String类已经覆写过equals方法,所以String可以直接equals
本质上比较的是地址! -
compareTo方法的使用
compareTo方法是一个compareable接口中定义的一个方法,通常是基于自然顺序,比较对象的大小,其返回值是一个int类型值,其语法是 S1.compareTo(S2);若S1,S2相等,返回0;若S1小于S2,则返回值小于0,;若S1大于S2,则返回值大于0; -
compare方法的使用
compare方法是Comparator接口定义的一个方法,基于比较器,比较对象的大小,其用法与compareTo方法类似。 -
多嘴一句考试不考的
comparable是内部比较器,相当于你在对象内部实现了一个方法,在内部!
comparator是外部比较器,可以使用泛型,不同类也可以比较!
comparable写完可以直接arrays.sort
comparator不改变我们的对象(类定义)很安全
区别在于:
实现了comparable的对象直接就可以成为一个可以比较的对象,不过得在类中进行方法定义;
comparator在对象外比较,不修改实体类。
-
-
重载的顺序(顺序搞错了导致无法重载 改错题)
-
就近原则!
比如你传一个’a’进去,先找传参是char的重载函数,然后才是int,然后是long,然后是Character–>Serializable–>Object–>char… -
不难看出先在基本类型里面匹配最相近的,char–>int–>long;然后就会去找对象往上找,如果是基本数据类型肯定先找自动装箱类,Character因为实现了Serializable接口所以也是符合就近原则的,最后所有东西都继承了Object所以Object也很正常,而Char…为什么是最后一个是因为他是可变的
-
合理分析一下,首先我们不知道你会写几个进来,我们会优先找符合个数的重载函数,比如:
void say(char a);
void say(char…);
肯定先使用第一个只有一个参数的,这也很符合就近原则吧!!!!!
-
-
接口实现 implements和extend的区别(用混了 改错题)
-
关键字implements是一个类,实现一个接口用的关键字,它是用来实现接口中定义的抽象方法。实现一个接口,必须实现接口中的所有方法。使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)
还有几点需要注意:
(1)接口可以被多重实现(implements),抽象类只能被单一继承(extends)
(2)接口只有定义,抽象类可以有定义和实现
(3)接口的字段定义默认为:public static final, 抽象类字段默认是"friendly"(本包可见) -
因为接口和继承我在前面几个地方真的讲了很多,就不赘述了
- 程序的结果
- 可以看看数据结构的源码,跟着走就很快熟悉了代码的运行
-
-
方法调用(不能直接调用 需要类/对象的名字才能引用 改错题)
- new Person().eat();
- Person p1 = new person();
p1. eat(); - static void say();{}
say(); - static int say();{return 1;}
int a = say();
-
super和this的用法
super和this的异同:
super(参数):
调用基类中的某一个构造函数(应该为构造函数中的第一条语句)
this(参数):
调用本类中另一种形成的构造函数(应该为构造函数中的第一条语句)super:
它引用当前对象的直接父类中的成员
(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时)
如:super.变量名 super.成员函数据名(实参)
this:
它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)调用super()必须写在子类构造方法的第一行,否则编译不通过 每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
super()和this()均需放在构造方法内第一行。
尽管可以用this调用一个构造器,但却不能调用两个。this和super 不能同时出现在一个构造函数 里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
this
this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。
this的用法在java中大体可以分为3种:- 普通的直接引用
这种就不用讲了,this相当于是指向当前对象本身。 - 形参与成员名字重名,用this来区分:
- 引用构造函数
这个和super放在一起讲,见下面
super
super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。
super也有三种用法:- 普通的直接引用
与this类似,super相当于是指向当前对象的父类,这样就可以用super.xxx来引用父类的成员。 - 子类中的成员变量或方法与父类中的成员变量或方法同名
- super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。
this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。
- 普通的直接引用
class Person {
public static void prt(String s) {
System.out.println(s);
}
Person() {
prt("父类·无参数构造方法: "+"A Person.");
}//构造方法(1)
Person(String name) {
prt("父类·含一个参数的构造方法: "+"A person's name is " + name);
}//构造方法(2)
}
public class Chinese extends Person {
Chinese() {
super(); // 调用父类构造方法(1)
prt("子类·调用父类”无参数构造方法“: "+"A chinese coder.");
}
Chinese(String name) {
super(name);// 调用父类具有相同形参的构造方法(2)
prt("子类·调用父类”含一个参数的构造方法“: "+"his name is " + name);
}
Chinese(String name, int age) {
this(name);// 调用具有相同形参的构造方法(3)
prt("子类:调用子类具有相同形参的构造方法:his age is " + age);
}
public static void main(String[] args) {
Chinese cn = new Chinese();
System.out.println();
cn = new Chinese("codersai");
System.out.println();
cn = new Chinese("codersai", 18);
}
}
输出: