Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/232.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
理解Java内部类中的作用域_Java_Android_Scope_Inner Classes - Fatal编程技术网

理解Java内部类中的作用域

理解Java内部类中的作用域,java,android,scope,inner-classes,Java,Android,Scope,Inner Classes,在一个Android项目中,我使用下面的代码。我得到一个错误:变量tts可能尚未初始化。如果我更改了变量tts的声明位置,我就不会再得到错误。如果我注释掉内部OnInitListener类中引用tts的两行,我也不会再得到错误(但也不会发生任何有趣的事情) 因此,我推断,如果tts变量在封闭方法中声明(即使它被声明为final),则内部类无法“看到”它,但当它被声明为封闭类的实例变量时,它可以看到它 我来自JavaScript背景;显然,Java在此上下文中以不同的方式处理变量范围。如果您能解释

在一个Android项目中,我使用下面的代码。我得到一个错误:
变量tts可能尚未初始化
。如果我更改了变量tts的声明位置,我就不会再得到错误。如果我注释掉内部OnInitListener类中引用tts的两行,我也不会再得到错误(但也不会发生任何有趣的事情)

因此,我推断,如果
tts
变量在封闭方法中声明(即使它被声明为
final
),则内部类无法“看到”它,但当它被声明为封闭类的实例变量时,它可以看到它

我来自JavaScript背景;显然,Java在此上下文中以不同的方式处理变量范围。如果您能解释一下Java在引擎盖下做了什么,我将不胜感激,以便我能够理解这些差异

package com.example.texttospeech;

import android.speech.tts.TextToSpeech;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import java.util.HashMap;
import java.util.Locale;


public class MainActivity extends ActionBarActivity {

    //private TextToSpeech tts; // UNCOMMENT THIS...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testTextToSpeech();
    }

    private void testTextToSpeech() {
        final String toSpeak = getString(R.string.hello_world);
        final int mode = TextToSpeech.QUEUE_FLUSH;
        final HashMap hashMap = new HashMap<String, String>();

        final TextToSpeech tts; // ... AND COMMENT THIS OUT...

        tts = new TextToSpeech(getApplicationContext(),
                new TextToSpeech.OnInitListener() {
                    @Override
                    public void onInit(int status) {
                        if (status != TextToSpeech.ERROR) {
                            // ... OR SIMPLY COMMENT OUT THE NEXT TWO LINES
                            tts.setLanguage(Locale.UK);
                            tts.speak(toSpeak, mode, hashMap);
                        }
                    }
                });
    }
}
package com.example.texttospeech;
导入android.speech.tts.TextToSpeech;
导入android.support.v7.app.ActionBarActivity;
导入android.os.Bundle;
导入java.util.HashMap;
导入java.util.Locale;
公共类MainActivity扩展了ActionBarActivity{
//private TextToSpeech tts;//取消对此的注释。。。
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testTextToSpeech();
}
私有void testTextToSpeech(){
final String toSpeak=getString(R.String.hello\u world);
final int mode=TextToSpeech.QUEUE\u FLUSH;
final HashMap HashMap=新HashMap();
最后一个文本:说出tts;//…并将其注释掉。。。
tts=新的TextToSpeech(getApplicationContext(),
新的TextToSpeech.OnInitListener(){
@凌驾
公共无效onInit(int状态){
if(状态!=TextToSpeech.ERROR){
//…或者简单地注释掉下面两行
tts.setLanguage(Locale.UK);
说话(toSpeak、mode、hashMap);
}
}
});
}
}

在内部,
TextToSpeech.OnInitListener
实例将对
tts
的引用传递给它的隐式构造函数,但此时,
tts
尚未初始化,只是声明了(并且不能传递未初始化的变量(堆栈上的局部变量将始终是该变量)因为它没有值,所以它不适用于任何方法)。将新创建的
TextToSpeech
类型的对象分配给变量
tts
,该变量依赖于
TextToSpeech.OnInitListener
(构造函数)的实例,该实例依赖于
tts
->循环依赖关系


通过将
tts
声明为成员变量,它将自动初始化为
null
。由于
tts
是一个成员变量,
TextToSpeech.OnInitListener
实例在内部传递对
MainActivity
外部实例的隐式引用时,始终能够访问
tts
的当前值,
TextToSpeech.OnInitListener
实例将对
tts
的引用传递给它的隐式构造函数,但此时,
tts
尚未初始化,只是声明了(并且不能传递未初始化的变量(堆栈上的局部变量将始终是该变量)因为它没有值,所以它不适用于任何方法)。将新创建的
TextToSpeech
类型的对象分配给变量
tts
,该变量依赖于
TextToSpeech.OnInitListener
(构造函数)的实例,该实例依赖于
tts
->循环依赖关系


通过将
tts
声明为成员变量,它将自动初始化为
null
。由于
tts
是一个成员变量,
TextToSpeech.OnInitListener
实例将始终能够访问
tts
的当前值,因为它被传递到
MainActivity

的外部实例的隐式引用,我认为以稍微不同的方式编写此代码就足够了,以查看这里发生了什么

final TextToSpeech tts;

TextToSpeech.OnInitListener listener = new TextToSpeech.OnInitListener() {
  @Override
  public void onInit(int status) {
    tts.setLanguage(Locale.UK);
    tts.speak(toSpeak, mode, hashMap);
  }
}

tts = new TextToSpeech(getApplicationContext(), listener);
基本上,在
侦听器
实例化的那一刻,声明了
tts
,但它仍然不存在。这就是警告的内容。编译器不会向前看,如果您将
tts
设置为类变量,那么据它所知,您的程序可能会在实例化
tts
之前尝试使用
listener
。通过将
tts
声明放在同一本地范围内,可以避免这种风险


所以我建议做的是让
testTextToSpeech
返回对
tts
的引用:

private TextToSpeech tts;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    tts = testTextToSpeech();
}

private TextToSpeech testTextToSpeech() {
    final String toSpeak = getString(R.string.hello_world);
    final int mode = TextToSpeech.QUEUE_FLUSH;
    final HashMap hashMap = new HashMap<String, String>();

    final TextToSpeech tts = new TextToSpeech(getApplicationContext(),
            new TextToSpeech.OnInitListener() {
                @Override
                public void onInit(int status) {
                    if (status != TextToSpeech.ERROR) {
                        tts.setLanguage(Locale.UK);
                        tts.speak(toSpeak, mode, hashMap);
                    }
                }
            });
    }
    return tts;
}
private TextToSpeech tts;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tts=testTextToSpeech();
}
私有TextToSpeech testTextToSpeech(){
final String toSpeak=getString(R.String.hello\u world);
final int mode=TextToSpeech.QUEUE\u FLUSH;
final HashMap HashMap=新HashMap();
final TextToSpeech tts=新TextToSpeech(getApplicationContext(),
新的TextToSpeech.OnInitListener(){
@凌驾
公共无效onInit(int状态){
if(状态!=TextToSpeech.ERROR){
tts.setLanguage(Locale.UK);
说话(toSpeak、mode、hashMap);
}
}
});
}
返回tts;
}

我认为用稍微不同的方式编写这段代码就足够了,看看这里发生了什么

final TextToSpeech tts;

TextToSpeech.OnInitListener listener = new TextToSpeech.OnInitListener() {
  @Override
  public void onInit(int status) {
    tts.setLanguage(Locale.UK);
    tts.speak(toSpeak, mode, hashMap);
  }
}

tts = new TextToSpeech(getApplicationContext(), listener);
基本上,在
侦听器
被实例化的那一刻,声明了
tts
,但它仍然是d