答案:ABC
java不允许单独的方法,过程或函数存在,需要隶属于某一类中。——AB错
javaz中只有静态方法才是类的成员,非静态方法都是对象的成员。——C错
该方法是Java程序入口方法,JVM运行程序会先查找main()方法。public是修饰符,表示任何类和对象都可以访问,static表明是静态方法,即方法中代码存储在静态存储区,类被加载后,就可以使用该方法而不需要通过实例化对象来访问,直接类名.main()直接访问,JVM启动便是按照上述方法签名(必须有public和static修饰,返还值为void,且方法参数是字符串数组)来查找方法入口,若查到则执行,否则报错。
/*
实现了一个Java的HelloWorld的程序
实现步骤:
1.定义类
2.定义主方法
3.一条命令,控制台输出了HelloWorld
*/
public class HelloWorld1{ // 1.定义类
//main是程序的主方法,固定格式,程序的入口
public static void main(String[] args){ //2.定义主方法
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
package cn.itcast.demo;
/*
* 4.1.3
*/
class T{
public static void main(String[] args) {
System.out.println("T main");
}
}
public class Test {
//程序入口函数2
public static void main(String[] args) {
System.out.println("Test main");
}
}
Abstract,即抽象。笼统的描述一类东西。
特点:
abstract可以修饰类,也可以修饰方法;
abstract修饰的类可以被继承和实现,但是这个类本身不能被实例化;
抽象方法必须在抽象类中,抽象类中可以有非抽象的方法;
抽象类中可以没有抽象方法,这样做的作用是这个类不可以被实例化;
抽象类的子类在继承抽象类后,必须把父类中的抽象方法重写,否则子类也会自动变为抽象类;
抽象方法用于被子类继承后重写。即是父类的抽象方法是空的,必须由子类继承之后在子类中由子类实现,这可以达到不同子类可以根据自己的特性来定义自己从父类继承过来的抽象方法;
abstract不能与final关键字共存,因为final关键字修饰的类是不能被继承的;
abstract不能与private关键字共存,因为私有的东西不能继承;
abstract不能与static关键字共存,当static修饰方法时,该方法可以通过类名直接调用,而abstract修饰的抽象方法是不能被调用的;
abstract修饰的类中的普通方法可以通过该抽象类的子类直接调用。
当一个抽象类中的所有成员只有抽象方法时,便是一个接口,可以用关键字interface表示;
接口中的成员有两种:1.全局常量 2.抽象方法 ;
接口中的权限必须是public,若没写public,会自动加上public;
接口中有抽象方法,因此接口也是抽象类,不可以实例化。所以其子类也必须覆盖了接口中所有的抽象方法后,才能实例化,否则他也是一个抽象类。
package cn.itcast.demo;
/*
* 4.1.4
*/
public class Test1 {
//由于静态块不管顺序如何,都会在main()方法执行之前执行
static{
System.out.println("Hello World1");
}
public static void main(String[] args) {
System.out.println("Hello World2");
}
static{
System.out.println("Hello World3");
}
}
静态对象(变量)优先于非静态对象(变量)初始化。静态对象(变量)只初始化一次,非静态对象(变量)可多次初始化
父类优先于子类初始化
按照成员变量定义顺序进行初始化,即使变量定义散布在方法定义中,依旧在任何方法(包括构造函数)调用之前先初始化。
package cn.itcast.demo1;
public class Base {
static{
System.out.println("Base static block 1.父类静态变量 静态代码块");
}
{
System.out.println("Base block 3.父类非静态变量 非静态代码块");
}
public Base(){
System.out.println("Base constructor 4.父类构造函数");
}
}
package cn.itcast.demo1;
public class Derived extends Base{
static{
System.out.println("Derived static block 2.子类静态变量 静态代码块");
}
{
System.out.println("Derived block 5.子类非静态变量 非静态代码块");
}
public Derived(){
System.out.println("Derived constructor 6.子类构造函数");
}
}
package cn.itcast.demo1;
public class text {
public static void main(String[] args) {
new Derived();
}
}
作用域由花括号位置决定,决定了变量名可见性和生命周期。**Java变量类型三种:成员变量、静态变量和局部变量。**类的成员变量作用范围与类的实例化对象作用范围相同,当类被实例化,成员变量会在内存中分配空间并初始化,直到实例化对象生命周期结束,其生命周期才结束。
被static修饰成员变量被称为静态变量或全局变量,但静态变量不依赖于特定实例而是所有实例。只要一个类被加载,JVM就会给类静态变量分配空间,可以类名和变量名来访问。局部变量作用域与可见性为它所在的花括号内。
大家都知道类的成员变量和方法可以使用private和protected修饰。
使用private修饰,表示该类的成员只能在类的内部访问。
使用protected修饰,表示该类的成员可以被类的内部、同包下的其它类以及该类的子类访问。
从组织结构来分析:
类的成员(包过变量、方法、内部类等)的上层结构是类,而类的上层结构是包。
如果类可以使用private来修饰,表示该包下的这个类不能被其它类访问,那么该类也失去了存在的意义,所以不能使用private来修饰类。
如果类可以使用protected来修饰,表示该类所在的包的其它类可以访问该类;该类所在的包的子包的类可以访问该类,但是包没有继承的概念,所以后一句是不对。所以用protected来修饰类也是没有意义的。
同理default修饰也不可以。
综上,类只有public修饰。同样可用来解释为什么接口中成员的作用域修饰符都是public,其他修饰符不可以的原因
可以定义多个类,只能一个类被public修饰且与文件名必须相同。若文件无Public,则文件名是随便一个类名字即可。
package cn.itcast.demo1;
class Base1{
public void print(){
System.out.println("Base");
}
}
public class Derived1 extends Base1{
public static void main(String[] args) {
Base1 c = new Derived1();
c.print();
}
}
是特殊函数用于对象实例化初始化对象成员变量。
与类名相同无返还值;
可有多个,若不提供构造函数则提供默认,若提供则不创建默认;
可有0,1及1个以上参数;
伴随new调用,不由程序编写者直接调用,经由系统调用。
对象实例时调用仅一次;
完成对象初始化构造;
不能被继承不能被覆盖能重载;
子类可通过super显式调用,父类不提供无参构造函数则子类需要显式调用,反之可以不显式。优先执行父类构造后子类构造;
子父类均无定义构造函数,均生成默认无参构造,修饰符与当前类修饰符一致。
答案是可以,但是编译器不会建议我们这么做。它会给我们一个警告。
package cn.itcast.demo1;
public class Text1 {
public Text1(){
System.out.println("construct");
}
public void Text1(){
System.out.println("call Text1");
}
public static void main(String[] args) {
Text1 t = new Text1();//调用构造函数
t.Text1();//调用Text1方法
}
}
由于Java不支持多重继承,即一个类只有一个父类,为了克服单继承的缺点,Java引入了接口这一概念。接口是抽象方法定义的集合(也可以定义一些常量值),是特殊的抽象类。接口中只包含方法的定义,没有方法的实现。接口中的所有方法都是抽象的。接口中成员的作用域修饰符都是public,接口中常量值默认使用public static final 修饰。一个类可以实现多个接口,即实现了多重继承。
从书上看到上面那段话,我依然不清楚,接口到底是什么,用来干什么。为此上了知乎总结了一下:
与类相比较,类描述了一个实体,包括实体的状态,也包括实体可能发出的动作,并且描述了这个动作具体的实现步骤。而接口则只定义了一个实体可能发出的动作,没有具体的实现步骤,也没有任何状态信息。因此,接口就有点像一个规范、一个协议,是一个抽象的概念,而类实现了这个协议,满足了这个规范的具体实体,是一个具体的概念。当一组方法需要在很多类里实现,那么把它们抽象出来,做成一个接口规范。
在Java中,有些接口内部没有声明任何方法,也就是说,实现这些接口的类不需要重写任何方法,这些没有任何方法声明的接口又被叫做标识接口,标识接口对实现它的类没有任何语义上的要求,它仅仅充当一个标识的作用,用来表明实现它的类属于一个特定的类型。这个标签类似于汽车的标志图标,每当人们看到一个汽车的标志图标时,就能知道这款车的品牌。Java库中已经存在的标识接口有Cloneable 和 serializable 等。在使用时经常用instanceof 来判断实例对象的类型是否实现了一个给定的标识接口。
通过一个例子来说明标识接口的作用。例如要开发一款游戏,游戏里面有一个人物专门负责出去寻找有用的材料,假设这个人物只收集矿石和武器,而不会收集垃圾。下面通过标识接口来实现这个功能。
package cn.itcast.demo2;
public interface Stuff {
}
package cn.itcast.demo2;
//矿石
public interface Ore extends Stuff {
}
package cn.itcast.demo2;
//武器
public interface Weapon extends Stuff {
}
package cn.itcast.demo2;
//垃圾
public interface Rubbish extends Stuff {
}
package cn.itcast.demo2;
//金矿
public class Gold implements Ore {
public String toString(){
return "Gold";
}
}
package cn.itcast.demo2;
//铜矿
public class Copper implements Ore {
public String toString(){
return "Copper";
}
}
package cn.itcast.demo2;
public class Gun implements Weapon {
public String toString(){
return "Gun";
}
}
package cn.itcast.demo2;
public class Grenade implements Weapon {
public String toString(){
return "Grenade";
}
}
package cn.itcast.demo2;
public class Stone implements Rubbish {
public String toString(){
return "Stone";
}
}
package cn.itcast.demo2;
import java.util.ArrayList;
public class Test {
public static ArrayList collectStuff(Stuff[] s){
ArrayList al = new ArrayList();
for (int i = 0; i < s.length; i++) {
//只收集矿石和武器,不收集垃圾,instanceof-是否实现了一个给定的标识接口
if(!(s[i]instanceof Rubbish)){
al.add(s[i]);
}
}
return al;
}
public static void main(String[] args) {
Stuff[] s = {new Gold(),new Copper(),new Gun(),new Grenade(),new Stone()};
ArrayList al = collectStuff(s);
System.out.println("The useful Stuff collected is:");
for (int i = 0; i < al.size(); i++) {
System.out.println(al.get(i));
}
}
}
在上例中,设计了三个接口:Ore 、Weapon 和 Rubbish 分别代表矿石、武器和垃圾,只要是实现Ore 或 Weapon 的类,游戏中的角色都会认为这是有用的材料,例如Gold、Copper、Gun、Grenade,因此会收集;只要是实现Rubbish 的类,都会被认为是无用的东西,例如Stone,因此不会收集。
java 1.8开始支持接口中定义静态方法,发了一波纠错终于得到回应,题目加了条件java8中
eclipse中测试了一下,提示的是:Illegal modifier for the interface method a; only public & abstract are permitted
你既然定义了interface(接口),那肯定是要其它的类去实现它的, 不然你定义它干吗,所以不能用protected,private 去修饰, 而要用public去修饰。
接口可以去继承一个已有的接口。
new语句返还指针引用。基本数据类型按值传递(输入参数复制),其他是按引用传递(对象的一个引用)。对象除了在函数调用时是引用传递,在使用“=”赋值也是采用引用传递。
Object类提供clone()方法,该方法返还object对象复制,该复制函数返还新对象而非引用。
使用步骤:实现clone类要继承Cloneable接口,类中重写Object类的clone()方法,在clone方法调用super.clone()。super.clone会直接或间接调用Object类的clone()方法。把浅复制的引用指向原型对象新的克隆体。
非基本类型的属性需要clone()方法才能完成深复制。
package cn.itcast.demo3;
public class Obj {
private String str = "default value";
public void setStr(String str){
this.str = str;
}
public String toString(){
return str;
}
}
package cn.itcast.demo3;
public class TestRef {
private Obj aObj = new Obj();
private int aInt = 0;
public Obj getAObj(){
return aObj;
}
public int getAInt(){
return aInt;
}
public void changeObj(Obj inObj){
inObj.setStr("changed value");
}
public void changeInt(int inInt){
inInt = 1;
}
public static void main(String[] args) {
TestRef oRef = new TestRef();
System.out.println("=======引用类型======");
System.out.println("调用changeObj()前:" + oRef.getAObj());
oRef.changeObj(oRef.getAObj());
System.out.println("调用changeObj()后:" + oRef.getAObj());
System.out.println("=======基本数据类型======");
System.out.println("调用changeInt()前:" + oRef.getAInt());
oRef.changeInt(oRef.getAInt());
System.out.println("调用changeInt()后:" + oRef.getAInt());
}
}
package cn.itcast.demo3;
public class Obj1 {
private int aInt = 0;
public int getAInt(){
return aInt;
}
public void setAInt(int int1){
aInt = int1;
}
public void changeInt(){
this.aInt = 1;
}
}
package cn.itcast.demo3;
public class TestRef1 {
public static void main(String[] args) {
Obj1 a = new Obj1();
Obj1 b = a;
b.changeInt();
System.out.println("a:" + a.getAInt());
System.out.println("b:" + b.getAInt());
}
}
1)实现clone的类首先需要继承Cloneable接口
2)在类中重写Object类中的.clone方法
3)在clone方法中调用super.clone()
4)把浅复制的引用指向原型对象新的克隆体
package cn.itcast.demo4;
public class Obj implements Cloneable {
private int aInt = 0;
public int getAInt(){
return aInt;
}
public void setAInt(int int1){
aInt = int1;
}
public void changeInt(){
this.aInt = 1;
}
public Object clone(){
Object o = null;
try {
o=(Obj)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
package cn.itcast.demo4;
public class TestRef {
public static void main(String[] args) {
Obj a = new Obj();
Obj b = (Obj)a.clone();
b.changeInt();
System.out.println("a:" + a.getAInt());
System.out.println("b:" + b.getAInt());
}
}
当类中包含一些对象时,就需要用到深复制;
实现方法是在对对象调用clone()方法完成复制之后,接着对对象中的非基本类型的属性也调用clone方法完成深复制。
package cn.itcast.demo5;
import java.util.Date;
public class Obj implements Cloneable {
private Date birth = new Date();
public Date getBirth(){
return birth;
}
public void setBirth(Date birth){
this.birth = birth;
}
public void changeDate(){
this.birth.setMonth(4);
}
public Object clone(){
Obj o = null;
try {
o=(Obj)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
//实现深复制
o.birth = (Date)this.getBirth().clone();
return o;
}
}
package cn.itcast.demo5;
public class TestRef {
public static void main(String[] args) {
Obj a = new Obj();
Obj b = (Obj)a.clone();
b.changeDate();
System.out.println("a:" + a.getBirth());
System.out.println("b:" + b.getBirth());
}
}
反射允许程序在运行时进行自我检查,同时也允许对其内部的成员进行操作,能够实现在运行时对类进行装载。
1)得到一个对象所属的类
2)获取一个类的所有成员变量和方法
3)在运行时创建对象(主要)
4)在运行时调用对象的方法
1)class.forName(“类的路径”);
2)类名.class类名.class
3)实例.getClass()实例.getClass()
package cn.itcast.demo;
public class Sub extends Base {
public void f(){
System.out.println("Sub");
}
public static void main(String[] args) {
//使用反射机制加载类
try {
//第一种:通过类名全路径获得:
//Class c = Class.forName("cn.itcast.demo.Sub");
//第二种:通过类名获得
//Class c = Sub.class;
//第三种:通过实例对象获得:Class> class = object.getClass();
Class c = new Sub().getClass();
Base b = (Base) c.newInstance();
b.f();
} catch (Exception e) {
// TODO: handle exception
System.out.println(e);
}
}
}
1) 通过new语句实例化一个对象
2)通过反射机制创建对象
3)实通过clone()方法创建一个对象
4)通过反序列化的方式创建对象
1)提供多层命名空间,解决命名冲突
2)对类按功能进行分类,使项目的组织更加清晰
package cn.itcast.demo11;
public class TestPackage {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
1)每个源文件开头加上"package packagename",然后源文件所在目录下创建一个新目录,名为packagename。
2)用javac指令编译每个sourcename.java源文件,将生产的sourcename.classname 文件名复制到packagename目录。
3)用java指令运行程序:java packagename.sourcename
下列说法正确的是
A.java中包的主要作用是实现跨平台功能
B.package语句只能放在import语句后面
C.包(package)由一组类(class)和接口(interface)组成
D.可以用#include关键词来标明来自其它包中的类
解答:
A: java中"包"的引入的主要原因是java本身跨平台特性的需求。实现跨平台的是JVM。
B: package语句是Java源文件的第一条语句。(若缺省该语句,则指定为无名包。),如果想在另一个类里面引用包里面的类,要把名字写全。(相当用文件的绝对路径访问)或者用import导入。
D:java中并无#include关键字, 如果想在另一个类里面引用包里面的类,要把名字写全。(相当用文件的绝对路径访问)或者用import导入。
C:正确
C语言函数指针重要功能是实现回调函数。回调函数指在某处注册,在某个需要的时候调用。
回调函数用于截获信息、获取系统消息或处理异步事件。
Java可以使用类和接口实现该效果。先定义一个接口,接口中声明要调用方法,接着实现该接口,用实现该类的对象作为参数传递调用程序,程度通过该参数调用指定函数实现回调功能。
例:程序员张三写了一段程序a,其中预留有回调函数接口,并封装好了该程序。程序员李四要让a调用自己的程序b中的一个方法,于是他通过a中的接口回调属于自己的程序b中的那个方法。
例:在实现排序算法时,可以通过传递一个函数指针来决定两个数的先后顺序,从而最终决定该算法是按升序还是降序排列。
具体而言:先定义一个接口,然后在接口中声明要调用的方法,接着实现这个接口,最后把这个实现类的一个对象作为参数传递给调用程序,调用程序通过这个参数来调用指定的函数,从而实现回调函数的功能。
package cn.itcast.demo10;
//接口中定义了一个用来比较大小的方法
public interface IntCompare {
public int cmp(int a,int b);
}
package cn.itcast.demo10;
public class Cmp1 implements IntCompare {
public int cmp(int a, int b) {
if(a > b){
return 1;
}else if(a < b){
return -1;
}else{
return 0;
}
}
}
package cn.itcast.demo10;
public class Cmp2 implements IntCompare {
public int cmp(int a, int b) {
if(a > b){
return -1;
}else if(a < b){
return 1;
}else{
return 0;
}
}
}
package cn.itcast.demo10;
public class Test {
public static void insertSort(int[] a,IntCompare cmp){
if(a!=null){
for (int i = 1; i < a.length; i++) {
int temp = a[i],j = i;
if(cmp.cmp(a[j-1], temp) == 1){
while(j >= 1 && cmp.cmp(a[j-1], temp) == 1){
a[j] = a[j-1];
j--;
}
}
a[j] = temp;
}
}
}
public static void main(String[] args) {
int[] array1 = {7,13,19,40,4,7,1};
insertSort(array1, new Cmp1());
System.out.println("升序排列:");
for(int array : array1){
System.out.print(array + "\t");
}
System.out.println();
int[] array2 = {7,13,19,40,4,7,1};
insertSort(array2, new Cmp2());
System.out.println("降序排列:");
for(int array : array2){
System.out.print(array + "\t");
}
}
}