Deixo aqui um conjunto de notas que poderão vir a ser úteis para quem vier a tirar a certificação
OCPJP6 - Oracle Certified Professional Java Programmer 6 (
exame 1Z0-851)
. Esta certificação era conhecida como
SCJP6.
Estas notas não são exaustivas e não são o suficiente para passar o exame. Há que estudar bastante para lá chegar. Obviamente que os que programam em Java à bastante tempo estão em significativa vantagem para fazer o exame.
Alguns pontos são básicos, outros mais complexos, mas todos servem para reforçar alguns aspectos que na utilização diária passam despercebidos. Parte dos títulos das notas estão em inglês pois são de uso comum na comunidade e não faz sentido traduzir as mesmas, pois o exame é em inglês.
Antes de mais recomendo vivamente o livro
SCJP Sun Certified Programmer for Java 6 Study Guide
que serve tanto para a certificação
OCPJP6 como para a
OCMJ6D - Oracle Certified Master, Java SE 6 Developer (ex-
SCJD6).
E sem mais demoras as notas de estudo.
Identificadores legais:
- todos os começados por letras
- $ (dólar)
- _ (sublinhado)
Palavras reservadas:
- const
- goto
- native
- strictfp
- assert
- enum
- há mais...
strictfp: Pode ser usada numa
classe ou
método. Se uma classe for marcada como strictfp, então qualquer método na classe irá ser conforme as regras do standard
IEEE 754 para vírgulas flutuantes e respectivas operações. Se não for usado, então as vírgulas flutuantes e respectivas operações são dependentes da plataforma. Pode-se marcar apenas um método como sendo
strictfp.
native: apenas pode ser aplicado a métodos, e a sua declaração é semelhante a um método
abstract.
Não há conflitos possíveis entre:
- Nomes de classes
- Type parameter placeholders
- Identificadores de variáveis
JavaBeans property naming rules:
- As assinaturas dos métodos setter têm de ser
- public
- retornar void
- ter um argumento que representa o tipo da propriedade
- As assinaturas dos métodos getter têm de ser
- public
- não têm argumentos de entrada
- tipo de retorno igual ao tipo de argumento do método setter para essa propriedade
JavaBeans listener naming rules:
- Os nomes dos métodos dos listeners usados para "registar" um listener com uma fonte de evento tem de usar o prefixo add, seguido do tipo de listener [ex: addActionListener(ActionListener al)]
- As regas para remover ("desregistar") são iguais ás do add excepto que o prefixo é remove [ex: removeMyListener(MyListener m)]
- O tipo de listener a adicionar ou remover tem de ser passado como argumento do método
- Os nomes dos métodos do listener têm de terminar com a palavra "Listener"
Source file declaration rules:
- Pode haver apenas uma classe pública no ficheiro fonte
- Pode haver mais do que uma classe não pública num ficheiro fonte
- Num ficheiro sem classes públicas, o nome do ficheiro pode ser diferente de quaisquer classes nele contidas
Modificadores de acesso (visibilidade)
|
Qualquer classe no mesmo pacote |
Qualquer classe (não subclasse) fora do pacote |
Própria classe |
Subclasse no mesmo pacote |
Subclasse pacote diferente |
* Através de herança |
default | OK | NA | OK | OK | NA |
public | OK | OK | OK | OK | OK |
private | NA | NA | OK | NA | NA |
protected | OK | NA | OK | OK | OK (*) |
O modificador de acesso
protected tem um efeito nas classes que pertençam a pacotes diferentes da superclasse, que é estes serem visíveis
apenas através de herança. Isto é, se uma subclasse que esteja num pacote diferente da superclasse instanciar a superclasse e através desta referência tentar aceder a um membro
protected, irá surgir um erro de compilação.
Declaração de Interfaces:
Todos os métodos declarados numa interface são automaticamente:
e estes modificadores podem ser omitidos total ou parcialmente. Só estes são permitidos!
Todas as variáveis definidas numa interface têm de ser:
ou seja, apenas é permitida a declaração de constantes. Não é preciso usar os modificadores. Podem ser omitidos ou usados intercaladamente.
Encapsulation:
- Protecção dos dados (com modificadores de acesso)
- Proteger as variáveis de instância
- Assessores públicos ao invés de acesso directo a variáveis de instância (usando a metodologia dos Javabeans)
Variable argument list (var-args)
Uso: tipo... variável
Só pode existir um var-arg na assinatura de um método e o var-arg tem de ser o último parâmetro.
Intervalos para os primitivos
Regra geral para intervalos
Positivos: 2
(nº bits -1) - 1
Negativos: -2
(nº bits -1)
Tipo |
Bits |
Intervalo Menor |
Intervalo Maior |
byte | 8 | -27 | 27 - 1 |
short | 16 | -215 | 215 - 1 |
int | 32 | -231 | 231 - 1 |
long | 64 | -263 | 253 - 1 |
float | 32 | NA | NA |
double | 64 | NA | NA |
char | 16 | NA | 216 - 1 (sem sinal) |
O tipo
char é representado em
Unicode. Pode-se indicar o valor do carácter directamente em unicode. ex:
\uxxxx ao invés de representar o carácter directamente. Cada carácter numa
String é representado como um
char.
O tipo
double é a representação por defeito para números de vírgula flutuante. Podem opcionalmente ser terminados em
D ou
d.
O tipo
float tem de ter
F ou
f na terminação.
Um literal inteiro é sempre um
int implicitamente
O resultado de uma expressão envolvendo qualquer coisa do tamanho int ou inferior é sempre int. Por exemplo: a soma de dois
byte é sempre um int.
Modificadores possíveis em variáveis e métodos
Variáveis Locais e Method Local Inner Classes | Variáveis Não Locais | Métodos e Inner Classes |
1- Não aplicável a Inner Classes
2 - Só aplicável a Method Local Inner Classes |
final
abstract 2
| final
public
protected
static
transient
volatile
| final
public
protected
private
static1
abstract
synchronized1
strictfp
native1 |
Ao contrário das variáveis não locais, as variáveis locais
não têm inicializações por defeito.
A inicialização de uma variável
final tem de ocorrer antes do construtor(es) terminar(em).
Declaração de Arrays
Constituição de um array:
int[] xpto = new int[4] {1, 2, 3, 4} ;
_______ __________ __________
Declaração Construção Inicialização
Regras gerais:
- Na parte da construção é obrigatório indicar o tamanho do array se não existir a parte da inicialização; se tiver inicialização então é opcional
- A parte parte da construção pode ser omitida se a inicialização vier no mesmo statement
Num array multidimensional apenas é obrigatório indicar na parte da construção o tamanho da primeira dimensão, caso não haja inicialização.
Os
[] podem estar intercalados com o identificador.
O tamanho do array apenas pode ser declarado na inicialização do mesmo, isto é, à direita do
=.
Ex: int[] array = new int
[10];
Declaração de enumerados
enum xpto
{X, Y, Z
};
Só podem ser declarados:
- na sua própria classe
- como um membro da classe
- tal como uma classe dentro de um ficheiro de uma classe pública
Os
enum não podem ser declarados dentro de métodos!
Tal como numa
não inner classe (quando o
enum é declarado como tal), apenas se pode aplicar os modificadores:
Se mais nenhuma declaração se seguir ao enum, então o ; (ponto e vírgula) é opcional.
A ordem pela qual os valores no enum são declarados conta! Isto porque o método
values() presente em todos os enums, retorna um array do tipo do enum com os valores pela ordem da declaração.
Num
enum é possível fazer override a métodos do próprio
enum.
Exemplo:
enum Xpto{
A(1),
B(2){
// Este bloco denomina-se: Constant Specific Class Body
public String getXptoza(){
return "ABC";
}
};
Xpto(int i){
this.i = i;
}
private int i;
public String getXptoza(){
return "Z";
}
} |
Uma classe que implemente uma interface:
- Não pode declarar novas checked exceptions para os métodos implementados
- Não pode declarar excepções que são mais abrangentes que as excepções declaradas no método da interface
- Pode declarar Runtime Exceptions em qualquer método da interface independentemente da declaração da interface
- Não é obrigatório declarar todas as excepções da interface (pode mesmo não declarar nenhuma)
IS-A: Passa o teste do
instanceof (uso de
implements e
extends)
HAS-A: Baseado no uso e não na herança. Ou seja, uma classe
has-a outra se o código da primeira classe tiver uma referência para uma instância da segunda.
Herança, Overriding, Overloading e Polimorfismo
Invocação de métodos polimórficos aplica-se apenas a métodos de instância overrriden! Apenas métodos de instância overriden são invocados dinamicamente baseados no tipo real de objecto.
A escolha de qual método overloaded invocar não é decidida dinamicamente em runtime. O tipo de referência (não o tipo de objecto) determina o método overloaded que é invocado.
O compilador apenas "olha" para o tipo de referência e não ao tipo de instância.
Os métodos
abstract, quando concretizados pelas subclasses, são sempre do tipo override.
Os métodos static não podem ser overriden!
As variáveis de instância também podem ser overrided.
Resumindo:
- overriding: decidido em runtime baseado no tipo de objecto
- overloading: baseado no tipo de referência do argumento passado em tempo de compilação
Escolha de métodos overloaded
Não esquecer: O código tem de ser retro-compatível sempre! Por isso comportamentos anteriores são sempre preferidos!
- widening é preferido sobre o boxing
- widening é preferido sobre var-args
- boxing é preferido sobre var-args
- var-args é sempre o último recurso
Regras de overriding
Regras para o método que está a fazer o override
em relação ao
método overriden
:
- Modificador de acesso
- Não pode ter um modificador de acesso mais restritivo
- Pode ter um modificador menos restritivo
- Retorno
- O tipo de retorno tem de ser o mesmo, ou um subtipo do tipo declarado
- Excepções (em relação às excepções declaradas na assinatura do método overriden)
- Pode lançar quaisquer excepções não checadas (que estendam RuntimeException)
- Não pode atirar novas excepções checked
- Não pode atirar excepções que sejam mais abrangentes
- Pode atirar excepções que sejam subclasses
- Pode lançar (declarar) menos ou nenhuma excepção
Casting
- upcasting - o cast é implícito, é opcional fazer o cast
- downcasting - o cast é obrigatório. É verificado apenas se o cast é possível, isto é, se os tipos estão na árvore de herança. Se não estiverem na árvore de herança dá erro de compilação.
Implementação de interfaces
- Seguir todas as regras para os overrides legais
Uma interface pode estender outras (uma ou mais ao mesmo tempo).
extends tem de preceder implements caso uma classe use os dois.
Se uma superclasse implementar uma interface, e se uma subclasse indicar explicitamente que também implementa a mesma interface, a subclasse não tem de voltar a implementar os métodos da interface, quando a superclasse já o fez. Não faz mal voltar a tornar explícito a indicação de implementação da interface.
Regras para construtores
- Pode existir um método com o mesmo nome da classe, mas este não ser um construtor (basta retornar algo)
- O construtor por defeito e sem argumentos apenas é automaticamente criado pelo compilador, se nenhum outro construtor for declarado
- A chamada a outro construtor ou a um construtor da superclasse é o primeiro statement (a primeira instrução) de cada construtor. O compilador pode inserir a chamada a super() caso não exista nenhuma chamada a outro construtor
- Não pode ser efectuada nenhuma chamada a métodos de instância ou acesso a variáveis de instância até depois do super construtor ter corrido (o construtor da superclasse). (Daí a chamada a outros construtores ter de estar na primeira linha)
- O uso de variáveis estáticas e métodos estáticos é permitido na chamada a outros construtores da classe
- As classes abstract têm construtores que são sempre chamados quando uma subclasse concreta é instanciada
- Um construtor apenas pode ser invocado dentro de outro
- Os construtores não são herdados!
- Os construtores não podem ser marcados como:
Construtor default
- Tem o mesmo modificador de acesso da classe
- Incluí ele próprio uma chamada a super()
O compilador dará erro se uma subclasse tiver um construtor onde ele tenha de colocar uma chamada implícita a
super() e a superclasse não tiver um construtor sem argumentos. Neste caso a chamada tem de ser feita à mão, colocando a chamada ao construtor da superclasse com argumentos.
static e o compilador
No acesso a coisas
static, o compilador apenas tem em atenção o tipo declarado da variável que está a aceder ao
static, ou seja,
é independente da variável de instância (o que conta é o tipo da variável de referência e não o tipo de objecto).
Coupling e Cohesion
Coupling - Até que ponto uma classe está ligada às demais. Ou seja, até que ponto alterações numa classe afectam outras.
Cohesion - Como é que uma dada classe é desenhada. Até que ponto uma classe tem um único e bem focado propósito.
Heap e Stack
Heap -
Onde estão as variáveis de instância e os objectos.
Stack - Onde estão as variáveis locais.
Números octais, decimais e hexadecimais
Números octais -
Todos os números inteiros começados por
0 (zero) podem ter até
21 dígitos.
Números hexadecimais - Todos os números começados por
0x (zero x). Podem ter até
16 dígitos (a representação das letras
não é case sensitive).
Por defeito, os números em octal, decimal, ou hexadecimal são
ints, a não ser que sejam terminados por
L ou
l (L minúsculo) sendo então
longs.
Narrowing e Widening
Sendo
Maior e
Menor tipos de dados
:
Maior
------------
Narrowing (cast obrigatório) ----------------- > Menor
Maior
<-----------
Widening (cast opcional. é implícito) ---------- Menor
"Escala":
double >
float >
long >
int >
short >
byte
Existe o
caso especial do char. Uma vez que o
char é um inteiro sem sinal de
16 bits só é possível fazer
widening a partir de
int. Todo e qualquer cast de outro tipo de dados numérico (
double,
float,
long,
int,
short ou
byte) para
char é sempre
narrowing. Detalhes completos disponíveis na
especificação.
Os operadores de atribuição compostos (+=, -=, *=, /=) colocam automaticamente um cast, não sendo necessário, por isso, escrevê-lo.
Valores por defeito de variáveis não locais atribuídos pelo compilador
- Referência para objecto: null
- byte, short, int, long: 0 (zero)
- float, double: 0 (zero)
- boolean: false
- char: '\u0000' (u seguido de zeros)
Se uma
referência de array for construída mas não for inicializada dentro do array serão colocados os mesmos valores que o tipo dos valores têm na inicialização por defeito. Isto é verdade quer para variáveis locais ou de instância.
Todas as variáveis locais têm de ser inicializadas antes de serem usadas. Caso não sejam usadas não é obrigatório inicializadas.
Arrays
Arrays são sempre objectos!
Blocos de inicialização
- Estáticos
- de Instância - correm imediatamente depois de todos os super construtores terem corrido. Correm pela ordem que aparecem no ficheiro fonte
Classes wrapper
As
classes wrapper (de tipos primitivos como por exemplo
Integer) tal como a classe
String são
imutáveis. O seu valor depois de atribuído não pode ser alterado.
Exceptuando a classe
Character cujo construtor apenas recebe um
char, todos os outros construtores das outras classes wrapper podem receber uma
String ou o tipo que fazem wrap.
A partir do Java 5, o objecto
Boolean pode ser usado num teste booleano.
Criação de objectos wrapper:
- Usando um construtor
- Usando o método estático valueOf() [tomar em atenção que a classe Character não tem este método]
Conversão de um numérico wrapped para um primitivo (
Character e
Boolean não têm):
- xxxValue()
- parseXxx() [estático]
Apenas os inteiros podem ter radix.
| Boolean | Byte | Character | Double | Float | Integer | Long | Short |
xxxValue |
| X |
| X | X | X | X | X |
parseXxx |
| X |
| X | X | X | X | X |
parseXxx
com radix |
| X |
|
|
| X | X | X |
valueOf | X | X |
| X | X | X | X | X |
valueOf
com radix |
| X |
|
|
| X | X | X |
toString(primitivo) | X | X | X | X | X | X | X | X |
toString(primitivo)
com radix |
|
|
|
|
| X | X |
|
toXxxString
Octal, hex ou bin |
|
|
|
|
| X | X |
|
Para o exame é necessário saber bem estes métodos, em que classes existem, etc.
Boxing e Autoboxing
Ao invés de se ter de:
- criar o wrapper
- tirar o primitivo de dentro do wrapper
- usar o primitivo
- voltar a criar um wrapper
Pode-se usar o objecto como primitivo que a VM trata do resto.
No caso dos operadores != e ==, a comparação entre um primitivo e um objecto wrapped é feita do seguinte modo:
- Os objectos são unwrapped e a comparação será primitivo a primitivo
Duas instâncias dos seguintes objectos wrapper (criadas através de boxing), serão sempre iguais (comparação com o operador ==) quando os seus primitivos forem do mesmo valor:
- Boolean
- Byte
- Character -> de \u0000 (0) a \u007F (127)
- Short -> de -128 a 127
- Integer -> de -128 a 127
O
Boxing e o
unboxing funcionam, de um modo geral, nos mesmos locais onde normalmente se usam primitivos ou um objecto wrapped.
As classes wrapper não podem fazer widden umas para as outras.
O que é e não é permitido (no
boxing e
widening):
- widden seguido de box não é permitido
- box seguido de widen é permitido
Garbage Collector (GC)
O
Garbage Collector (GC) limpa apenas a heap (
no que ao exame diz respeito).
Método finalize()
- Para qualquer objecto, finalize() será apenas chamado uma e uma só vez no máximo pelo GC
- Chamar o método finalize() pode fazer com que o objecto não seja apagado
- Poderá nunca ser executado
Operadores
Nos operadores compostos (+=, -=, *=, /=) a expressão à direita tem sempre precedência.
Na comparação entre um carácter com outro ou com um numérico é usado o valor unicode do carácter como valor numérico.
Com os operadores
== ou
!= apenas de pode comparar tipos compatíveis.
Nos
enum == ou
equals() dão o mesmo resultado.
instanceof não pode ser usado para testar duas classes hierárquicas diferentes (dá erro de compilação).
Operador condicional :
variável = (expressão_booleana) ? valor_a_atribuir_ se_Verdade : valor_a_atribuir_se_Falso;
&& - short-circuit AND
& - non-short-circuit AND
!! - short-circuit OR
| - non-short-circuit OR
Switch
switch (expression) {
case constant1: code block
case constant1: code block
default: code block
}
Uma expressão (
expression) no
switch tem de ser avaliada como:
char,
byte,
short,
int ou
enum, ou seja, apenas
enums e variáveis que possam implicitamente ser promovidas a
int podem ser usadas!
A constante do
case tem de ser avaliada tal qual a expressão (
expression) do
switch e
ainda tem de ser uma constante em tempo de compilação!
O
default case pode vir em qualquer posição do
case.
Ciclo for
No ciclo for todas as partes da declaração são opcionais.
Na parte da inicialização todas as variáveis têm de ser do mesmo tipo. Na parte da condição o resultado tem de ser booleano. Na parte do incremento qualquer statement é válido!
No uso de
continue e
break com labels, ambos têm de estar dentro do loop que tem o mesmo nome da label. Caso contrário código não compila.
Assertions
Quando se usa assertions presume-se sempre que algo (o que se testa) é verdadeiro. Caso não seja uma
AssertionError é lançada.
- assert (boolean_expression);
- assert (boolean_expression) : expressão_que_retorna_um_valor
A parte
expressão_que_retorna_um_valor é impressa apenas se uma
AssertionError for lançada.
assert só pode ser usado como identificador se o código for compilado com a opção:
-source 1.3
A opção de runtime
-ea ou
-enableassertions activa as assertions.
Apeser de por defeito as assertions estarem desligadas, as opções de runtime
-da ou
-disableassertions inactivam as assertions também.
A opção
-dsa desliga as assertions para as classes de sistema.
Pode-se combinar as opções de ligar e desligar assertions.
Pode-se ligar/desligar as assertions do seguinte modo:
- sem argumentos -> Todas as classes excepto as de sistema
- com nome de pacote -> Todas as classes do pacote indicado e também, subpacotes
- nome da classe -> Classe indicada
Exemplo:
-ea:pt.xpto.pacote
Mais informação em:
Excepções
Unchecked Exceptions
- RuntimeException (e subclasses)
- Error (e subclasses)
Excepção | Descrição | Normalmente Lançada Por |
IllegalStateException | Atirada quando o estado do ambiente não corresponde à operação que se está a tentar | Programaticamente |
ExceptionInInitializerError | Atirada quando se tenta inicializar uma variável ou bloco de inicialização estático | JVM |
String Constant Pool
Zona de memória onde são guardadas as
Strings pela
JVM. Se uma dada
String já existir, a
JVM apenas coloca uma referência extra para a
String, e um novo objecto não é criado.
Métodos mais importantes na classe String
É imprescindível para o exame saber de cor vários métodos em várias classes. Não há consulta disponível por isso tem de se decorar a API.
- char charAt(int)
- String concat (String)
- String replace(char o, char n)
- String toLowerCase()
- String toUpperCase()
- String trim()
- boolean equalsIgnoreCase(String)
- int length()
- String substring(int)
- String substring(int b, int e) - O e é exclusive
- Strint toString()
Não esquecer:
Arrays têm a propriedade
length pública para leitura. Nas
Strings só por acesso ao método
length()!
Métodos mais importantes na classe StringBuilder e StringBuffer
- StringXxx append(...)
- StringXxx delete(int s, int e) - O e é exclusive
- StringXxx insert(int o, ...)
- StringXxx reverse()
- String toString()
- boolean equals(Object) - Não compara os valores pois não é overriden!
Java io
Métodos principais na classe java.io.File
Um objecto do tipo
File pode representar ou um ficheiro ou uma directoria.
O construtor da classe
File não cria o ficheiro/directoria fisicamente. Apenas cria o nome do ficheiro/directoria.
- File(File, String)
- File(String, String)
- File(String)
- boolean createNewFile() - cria um ficheiro se ainda não existir
- boolean mkdir() - cria a directoria se ainda não existir
- boolean isFile()
- boolean isDirectory()
- boolean exists()
- boolean delete() - não apaga uma directoria se esta não estiver vazia
- String[] list()
- boolean renameTo(File)
Métodos principais na classe java.io.FileWriter
- FileWriter(File) -> Cria o ficheiro fisicamente
- FileWriter(String) -> Cria o ficheiro fisicamente
- close()
- write(...)
- flush()
Métodos principais na classe java.io.BufferedWriter
- BufferedWriter(Writer)
- close()
- newLine()
- flush()
- write(...)
Métodos principais na classe java.io.PrintWriter
- PrintWriter(File)
- PrintWriter(String)
- PrintWriter(OutputStream)
- PrintWriter(Writer)
- flush()
- close()
- format(...)
- write(...)
- print(...)
- printf(...)
- println(...)
- append(...)
Nota : Só o
mkdir() cria a directoria. Ao contrário do que ocorre com os ficheiros, as directorias não são criadas automaticamente pelos
Writers (dá excepção).
Métodos principais da classe java.io.FileReader
- FileReader(File)
- FileReader(String)
- int read(char[])
Métodos principais na classe java.io.BufferedReader
- BufferedReader(Reader)
- String readLine()
- read()
Métodos principais da classe java.io.Console
- String readLine(mascaraStr, promptStr)
- char[] readPassword(mascaraStr, promptStr)
- format(mascaraStr, ...) - escreve na consola
- format(String, ...) - escreve na consola
Nenhum dos parâmetros dos métodos da classe
Console pode ser
null. Caso algum seja uma
NullPointerException é lançada.
Obter o objecto
Console:
System.console(); - Pode retornar
null se a mesma não existir.
Métodos principais na classe java.io.ObjectOutputStream
- ObjectOutputStream(OutputStream) - OutputSteam é geralmente FileOutputStream
- writeObject(Object)
Métodos principais na classe java.io.ObjectInputStream
- ObjectInputStream(InputStream) - InputStream é geralmente FileInputStream
- Object readObject()
Métodos principais da classe java.io.FileInputStream
Métodos principais da classe java.io.FileOutputStream
Serialização
Para serem serializáveis as classes têm de implementar
Serializable.
Se um objecto não serializável (que não implementa
Serializable) for tentado ser serializado ocorre a excepção:
java.ioNotSerializableException.
Se todos os objectos do grafo de serialização forem serializáveis, não é preciso fazer nada. Caso contrário poderá ser necessário ajudar na serialização com estes dois métodos:
- private void writeObject(ObjectOutputStream) - pode lançar IOException
- deve-se invocar na primeira linha do método: os.defaultWriteObject
- private void readObject(ObjectInputStream) - pode lançar IOException e
ClassNotFoundException
- deve-se invocar na primeira linha do método: os.defaultReadObject
É recomendado tratar as excepções na serialização.
Criação de novos objectos e Serialização
Eventos
que ocorrem quando se usa
new para criar um novo objecto:
- Todas as variáveis de instância da classe têm atribuído os valores por defeito
- O construtor é invocado e, imediatamente, é chamado o construtor da superclasse
- Os construtores da superclasse completam (correm e terminam)
- As variáveis de instância que são inicializadas como fazendo parte da sua declaração vêm atribuído o seu valor inicial
- O construtor completa-se (corre e termina)
Esta ordem de eventos
não ocorre quando um objecto é desserializado! Quando uma instância de uma classe serializável, é desserializada:
- O construtor não corre
- Se uma classe serializável estender outra que não o é, o construtor da classe serializável não corre (como indicado no ponto anterior), mas o da superclasse irá correr, tal como todos os construtores de todas as superclasses acima da superclasse!
- As variáveis de instância não têm os seus valores iniciais atribuídos
- Só os valores que foram salvos (o estado do objecto na altura da serialização) serão reatribuídos
- As variáveis que não estão no estado do objecto terão os valores por defeito do tipo da variável
Métodos principais na classe java.util.Date
- Date()
- Date(long) - em milissegundos
- setTime(long) - em milissegundos
- long getTime() - em milissegundos
Métodos principais da classe java.util.Calendar
- Calendar getInstance()
- Calendar getInstance(Locale)
- add(...)
- setTime(Date)
- get(CALENDAR_CONSTANT)
- roll(...)
- Date getTime()
- set(int year, int month, int day) - month começa em 0
- CALENDAR_CONSTANT getFirstDayOfWeek()
O método
roll é igual ao método
add, exceptuando que no
roll os outros campos não são automaticamente incrementados ou decrementados. Só o campo indicado é que é.
Métodos principas da classe java.util.DateFormat
- DateFormat getInstance()
- DateFormat getDateInstance()
- DateFormat getDateInstance(int style)
- DateFormat getDateInstance(int style, Locale locale)
- String format(Date)
- Date parse(String)
O argumento
style pode ser:
- DateFormat.SHORT
- DateFormat.MEDIUM
- DateFormat.LONG
- DateFormat.FULL
Métodos principais da classe java.text.NumberFormat
- NumberFormat getInstance()
- NumberFormat getInstance(Locale)
- NumberFormat getNumberInstance()
- NumberFormat getNumberInstance(Locale)
- NumberFormat getCurrencyInstance()
- NumberFormat getCurrencyInstance(Locale)
- String format(Number)
- Number parse(String)
- int getMaximumFractionDigits()
- setMaximumFractionDigits(int) - Só se aplica na formatação
- setParseIntegerOnly(boolean)
Métodos principais da classe java.util.Locale
- Locale(String language)
- Locale(String language, String country)
- Locale getDefault()
- String getDisplayCountry()
- String getDisplayCountry(Locale)
- String getDisplayLanguage()
- String getDisplayLanguage(Locale)
Existe um conjunto de constantes que correspondem já a
Locales construídos. Ex:
Locale.GERMANY
Expressões Regulares (regex)
Métodos principais da classe java.util.regex.Pattern
- Pattern Pattern.compile(String regex)
- Matcher matcher(String)
- String pattern() - String Regex
Métodos principais da classe java.util.regex.Matcher
- boolean find() - Verifica se há um match/procura no próximo resultado
- int start() - Indices na String fonte onde começam os emparelhamentos
- Pattern pattern() - String regex. Só deve ser invocado se o método find retornar true.
- String group() - Resultado que encontrou. Só deve ser invocado se o método find retornar true.
- boolean matches() - Indica se toda a String fonte corresponde à expressão regular indicada.
Como regra geral, uma procura regex corre da esquerda para a direita, e assim que um carácter da fonte tiver sido usado num resultado (match), não pode ser reutilizado.
Metacaracteres
- \s - Um carácter whitespace
- \w - Um carácter palavra (letras, dígitos ou _ )
Quantificadores
Para se usar quantificadores em conjuntos
[....] tem de se colocar o conjunto entre parêntesis. Por exemplo:
([....])+
- ?, * e + são gananciosos. Basicamente lê a fonte toda e trabalha da direita para a esquerda. Assim que encontrar pára. Dá o resultado mais longo.
- ??, *? e +? são relutantes. Encontra o resultado mínimo.
Com os quantificadores gananciosos, o método
find da classe
Matcher pode retornar resultados (matches) do tamanho 0 (zero) , nas seguintes condições:
- Depois do último carácter da fonte
- Entre carácteres depois de um resultado ter sido encontrado
- No início da fonte
- No início de uma fonte com tamanho zero
java.util.Scanner
Usado para tokenização on-the-fly. Por defeito o delimitador é o espaço em branco.
Métodos principais
- Scanner(InputStream)
- Scanner(String)
- Scanner(File)
- String findInLine(String regex) - Usado em loops. Retorna null se não encontrar nada. Chamadas sucessivas encontram o próximo match.
- boolean hasNext() - Usado em loops. Não avança.
- String next() - Usado em loops. Obtém e avança para o próximo.
- boolena hasNextInt() - Usado em loops. Não avança.
- int nextInt() - Usado em loops. Obtém e avança para o próximo.
- boolean hasNextBoolean() - Usado em loops. Não avança.
- boolean nextBoolean() - Usado em loops. Obtém e avança para o próximo.
- useDelimiter(String regex)
Os métodos
hasXXX e
nextXXX existem para todos os primitivos excepto
char.
Os métodos
nextXXX só devem ser chamados se o método correspondente
hasXXX retornar
true. Caso contrário pode dar excepção.
String e Tokenizing
- String[] split(String regex) - Deve ser usado em Strings relativamente pequenas.
Os delimitadores usados no
Scanner e no split podem ser apenas expressões regulares. Exemplo: "
\d\d".
Formatação com printf e format da classe java.io.PrintStream
Ambos os métodos funcionam com os mesmos parâmetros:
printf(String format, Object... argumentos).
O parâmetro
format pode conter simultaneamente informação normal de literais
String que não estão associados a quaisquer argumentos e dados de formatação específicos de argumentos.
Explicação da parte format:
%[arg_index$][flags][width][.precision] conversion
Nota: entre [] são opcionais
arg_index$ - Um inteiro imediatamente seguido de
$. Indica qual argumento deve ser impresso nessa posição.
flag:
- - -> Alinhar à esquerda
- + -> Incluir o sinal (+ ou -)
- 0 -> Preencher com zeros
- , -> Usar separadores específicos do Locale
- ( -> Colocar entre parêntesis os números negativos
width - Indica o número mínimo de caracteres a imprimir.
precision - Usado em números de vírgula flutuante e indica o número de dígitos depois da vírgula.
conversion -O tipo de argumento a formatar:
- b - Booleano
- c - Carácter (char)
- d -Inteiro
- f - Vírgula flutuante
- s - String
Se o tipo indicado não condizer com o tipo de argumento uma
IllegalFormatConversionException ocorre (
RuntimeException).
Métodos principais da classe java.lang.Object
- boolean equals(Object) - Este método, se não for overrided, apenas usa o operador == para as comparações. Se este método não for overrided, então o objecto não será usável, por exemplo, como chave em Hashtables, pois a não ser que ainda se tenha referência para a chave, nunca a mesma será encontrada. Fazendo override a este método então deve-se fazer override ao método hashcode (por causa do contrato do equals e do hashcode).
- int hashCode() - O overriding deste método deve usar as mesmas variáveis de instância usadas no overriding do método equals. Por esta razão se for efectuado o override deste método então deve-se fazer também o overriding do método equals (contrato do hashcode e do equals).
- String toString() - Se não for overrided, retorna o nome_da_classe@hashcode do objecto (hexadecimal sem sinal).
- final void notify()
- final void notifyAll()
- final void wait()
- void finalize()
Contrato do equals()
- Reflexivo: x.equals(x) deve retornar true
- Simétrico: x.equals(y) = true se e só se y.equals(x) = true
- Transitivo: x.equals(y) = true e y.equals(z) = true => x.equals(z) = true
- Consistente: Múltiplas invocações de x.equals(y) consistentemente retornam true ou consistentemente retornam false, desde que os objectos não sejam modificados na informação usada no equals.
- x.equals(null) = false
- Se x.equals(y) = true => x.hashcode() = y.hashcode()
Contrato do hashcode()
- Consistente: Múltiplas invocações no mesmo objecto, durante a execução de uma mesma aplicação Java, retornam o mesmo inteiro, desde que nenhuma informação usada na comparação equals seja alterada.
- Se x.equals(y) = true => x.hashcode() = y.hashcode()
- Se x.equals(y) = false não implica que x.hashcode() <> y.hascode()
- Se x.hascode() = y.hashcode não implica que x.equals(y) = true
Nota: Variáveis
transient não são apropriadas para uso no
equals e
hashcode.
Ordem Natural dos Caracteres
Espaço em branco < UPPERCASE < lowercase
Collections
Propriedades principais das colecções
- ArrayList e Vector - Iteração rápida e acesso aleatório rápido.
- LinkedList - Iteração rápida e remoção rápida. Boa para adicionar elementos ao início ou ao fim. Serve para concretizar uma pilha ou fila.
- HashSet - Acesso rápido. Sem duplicados e sem ordem.
- LinkedHashSet - Sem duplicados e com ordem de iteração pela a de inserção.
- TreeSet - Sem duplicados. Por defeito a ordenação é feita pela ordem natural (ascendente).
- EnumMap - A chave tem de ser um enum e tem de pertencer ao tipo indicado. Chaves null não são permitidas (dá NullPointerException). Valores null são permitidos.
- HashMap - Actualizações rápidas. Só uma chave null e múltiplos valores null.
- Hashtable - Actualizações rápidas. null não é permitido em lado nenhum.
- LinkedHashMap - Iteração rápida. Mantém a ordem de inserção. Itera pela ordem de inserção ou último acesso.
- TreeMap - Por defeito, a ordenação é feita pela ordem natural ascendente.
- ConcurrentSkipListMap - log(n). null não permitidos em lado nenhum. Ordem natural.
- PriorityQueue - Priority-in, Priority-out. Os elementos são ordenados pela sua prioridade relativa. O construtor pode levar um comparador no 2º argumento.
Classe | Map | Set | List | Queue | Ordered | Sorted | Identificadores | Duplicados |
HashMap | X |
|
|
| Não | Não | Únicos(chave) | Sim (valores) |
Hashtable | X |
|
|
| Não | Não | Únicos(chave) | Sim (valores) |
TreeMap | X |
|
|
| Sim | Ordem Natural ou Costumizável | Únicos(chave) | Sim (valores) |
LinkedHashMap | X |
|
|
| Por Ordem de Inserção ou por Último Acesso | Não | Únicos(chave) | Sim (valores) |
ConcurrentSkipListMap | X |
|
|
| Ordem Natural | Não | NA | Sim (valores) |
EnumMap | X |
|
|
| Sim | Não | Únicos(chave) | Sim (valores) |
HashSet |
| X |
|
| Não | Não | NA | Não |
TreeSet |
| X |
|
| Sim | Ordem Natural ou Costumizável | NA | Não |
LinkedHashSet |
| X |
|
| Por Ordem de Inserção | Não | NA | Não |
ArrayList |
|
| X |
| Por Índice | Não | NA | Sim |
Vector |
|
| X |
| Por Índice | Não | NA | Sim |
LinkedList |
|
| X | X | Por Índice | Não | NA | Sim |
PriorityQueue |
|
|
| X | Sim | Por Prioridades ou Ordem Natural | NA | Sim |
Métodos principais da interface java.util.Set
- boolean add(Object)
- boolean remove(Object)
- int size()
- boolean contains(Object)
- Iterator iterator()
- Object[] toArray()
- Object[] toArray(Object[])
Métodos principais da interface java.util.List
- boolean add(int, Object)
- boolean add(Object)
- Object get(int)
- boolean remove(int)
- boolean remove(Object)
- int size()
- boolean contains(Object)
- int indexOf(Object)
- Iterator iterator()
- Object[] toArray()
- Object[] toArray(Object[])
Métodos principais da interface java.util.Queue
- Object peek() - Retorna o primeiro elemento da fila sem o remover
- Object pool() - Retorna o primeiro elemento da fila removendo-o
- boolean add(Object) - Adiciona o elemento à fila
- boolean offer(Object) - Adiciona o elemento à fila
Métodos principais da interface java.util.Map
- Object put(Object key, Object value)
- Object get(Object key)
- Object remove(Object key)
- int size()
- boolean contains(Object key)
- boolean contains(Object value)
- Set keySet()
As chaves nos
Map devem (
não é obrigatório mas nada será retornado) fazer override de
equals() e
hashCode().
Não esquecer que os
Maps funcionam em dois passos:
- Usam o método hashCode() para encontrar o balde certo (se o hashCode do objecto usado como chave mudar, o Map irá procurar o objecto no local errado!)
- Usam o método equals() para encontrar o objecto no balde
Métodos principais da classe java.util.Collections
- int Collections.binarySearch(List, Object)- Os objectos na lista têm de implementar Comparable!
- int Collections.binarySearch(List, Object, Comparator)
- void Collections.sort(List) - Os objectos na lista têm de implementar Comparable!
- void Collections.sort(List, Comparator)
- Comparator Collections.reverseOrder(List) - Os objectos na lista têm de implementar Comparable!
- Comparator Collections.reverseOrder(Comparator)
- void Collections.reverse(List)
Métodos principais da classe java.util.Arrays
- int Arrays.binarySearch(Object[], Object)
- int Arrays.binarySearch(Object[], Object, Comparator)
- void Arrays.sort(Object[]) - Os objectos no Object[] têm de implementar Comparable!
- void Arrays.sort(Object[], Comparator)
- List Arrays.asList(Object[]) - A lista e o array ficam ligados um ao outro. O Object[] não pode ser um array de primitivos
- boolean equals(Object[], Object[])
- String toString(Object[])
Métodos importantes na classe java.util.TreeSet
- Object ceiling(Object) - Elemento mais pequeno, maior ou igual ao objecto
- Object heigher(Object) - Elemento mais pequeno, maior que o objecto
- Object floor(Object) - Elemento maior, menor ou igual ao objecto
- Object lower(Object) - Elemento maior, menor que o objecto
- Object poolFirst() - Remove e devolve a primeira entrada
- Object poolLast() - Remove e devolve a última entrada
- NavigableSet descendingSet() - Retorna um NavigableSet por ordem inversa
- NavigableSet/SortedSet headSet(Object, Boolean) - Retorna o subconjunto que termina no elemento Object (*)
- NavigableSet/SortedSet tailSet(Object, Boolean) - Retorna o subconjunto que começa no elemento Object (*)
- NavigableSet/SortedSet subSet(Object start, Boolean, Object end, Boolean) - Retorna o subconjunto que começa no elemento Object start e termina no elemento Object end (*)
(*) - Os
Boolean são opcionais (Java 6). Indicam se o final é inclusive e retornam
NavigableSet. Caso não sejam usados os
Boolean, é retornado um
SortedSet.
Métodos importantes na classe java.util.TreeMap
- Object firstKey() - Retorna a primeira chave
- Object ceilingKey(Key) - Retorna a menor chave, maior ou igual a Key
- Object heigherKey(Key) - Retorna a menor chave, maior que Key
- Object floorKey(Key) -Retorna a maior chave, menor ou igual a Key
- Object lowerKey(Key) -Retorna a maior chave, menor que Key
- Object poolFirstEntry() - Retorna e remove o primeiro par chave-valor
- Object poolLastEntry() - Retorna e remove o último par chave-valor
- Map.entry lastEntry() -Maior chave no Map ou null se vazio.
- NavigableMap descendingMap() -Retorna um NavigableMap na ordem inversa
- NavigableMap/SortedMap headMap(Key, Boolean) - Submapa terminado em Key (*)
- NavigableMap/SortedMap tailMap(Key, Boolean) - Submapa começado em Key inclusivé (*)
- NavigableMap/SortedMap subMap(Key start, Boolean, Key end, Boolean) - Retorna o submapa começado em start e terminado em end (*)
(*) - Os
Boolean são opcionais (Java 6). Indicam se o final é inclusive e retornam
NavigableMap. Caso não sejam usados os
Boolean, é retornado um
SortedMap.
Os seis métodos de
TreeSet e
TreeMap que retornam subconjuntos, retornam subconjuntos que estão ligados aos conjuntos originais. Pode-se efectuar operações no subconjunto que irão afectar também o conjunto original. Se se adicionar/remover elementos ao conjunto original, estes serão igualmente adicionados/removidos do subconjunto
se os elementos estiveram dentro do intervalo.
Se se adicionar um elemento ao subconjunto que esteja fora do intervalo deste, irá atirar uma excepção. O mesmo não acontece se este mesmo elemento for adicionado ao conjunto original!
No
TreeSet e no
TreeMap os seus elementos têm de implementar
Comparable.
Collections e Código Legado
Na invocação de código legado com colecções que usam genéricos, se o código legado inserir algo na colecção que seja diferente do tipo especificado no genérico,
não irá dar erro de Runtime (embora se se usar o tipo guardado numa operação supostamente de outro tipo irá dar excepção). Contudo, em tempo de compilação, chamadas a métodos legados com colecções que usam genéricos e que inserem elementos nas colecções (se a inserção for invocada do código não legado) irá dar um aviso (warning) do género: A classe usa operações não seguras ou não checadas. Usar
-Xlint para ver detalhes.
Tomar em atenção que os métodos "get" das colecções retornam
Object. Se a colecção não usar
generics, então é obrigatório o uso de
casts, inclusive para primitivos e respectivos
wrappers. Não há
autoboxing automático. No "add" já há
autoboxing.
Pesquisa nas classes Arrays e Collections
O método
binarySearch das classes
Arrays e
Collections retorna:
- >= 0 - Índice do elemento procurado
- < 0 - Índice que presenta o ponto de inserção. Para calcular devidamente: ABS(ponto de inserção -1)
Os Arrays/Collections têm de estar ordenados antes de se proceder à procura. Caso contrário os resultados serão imprevisíveis.
Os Arrays/Collections têm de ser procurados com o mesmo tipo de ordenação que foi usado na ordenação dos mesmos (ordem natural ou usando um
Comparator).
Em tudo o que envolva ordenação (Collections, Arrays, Sets ordenados, etc), os objectos têm de ser mutuamente comparáveis (do mesmo tipo)!
Interface java.lang.Comparable - (implements Comparable)
- int compareTo(Object) - O Object pode ser implementado com o próprio tipo da classe (por causa dos generics)
Interface java.util.Comparator - (implements Comparator)
- int compare(Object, Object) - Os Objects podem ser implementados com o próprio tipo da classe (por causa dos generics)
Métodos principais da classe java.util.Iterator
- boolean hasNext()
- Object next()
Generics
A informação de
typing (do genérico) não existe em tempo de execução.
Só em tempo de compilação. Todo o código "
generics" é apenas para compilação.
Com
generics, atribuir a uma referência de um supertipo, um objecto de um subtipo (ou do mesmo tipo) mas com um
generic diferente do declarado, nunca irá compilar com
generics.
O tipo de uma declaração de variável tem de ser igual ao tipo que se passa. Não funciona nem com super nem subtipos.
Ou seja, o tipo de genérico da referência e o tipo de genérico do objecto ao qual se refere têm de ser idênticos.
O polimorfismo aplica-se apenas ao tipo base.
Tipo_Base <Tipo_Genérico> = Tipo_Base<Tipo_Genérico>;
O mesmo acontece na invocação de métodos. Não há polimorfismo com
generics.
O polimorfismo é permitido nos arrays. Em runtime a JVM sabe o tipo dos arrays, mas não sabe o tipo das colecções (por causa do compilador apagar o tipo -
Type Erasure).
O uso de
Tipo1, indica ao compilador que se pode aceitar qualquer subtipo (
?)
de genérico do tipo de argumento declarado (
Tipo2).
Esta indicação implica que nenhum objecto possa ser adicionado à colecção. Se tal suceder um erro de compilação ocorre. Esta indicação é uma excepção à regra do não polimorfismo dos
generics.
? extends - Usa-se quer para classes quer para interfaces.
O uso de
Tipo1, indica ao compilador que se pode aceitar qualquer tipo (
?) genérico do indicado (
Tipo2) e também qualquer supertipo do
Tipo2. Ou seja, toda a hierarquia superior do
Tipo2 e o próprio
Tipo2 são aceites.
Isto permite adicionar elementos à colecção.
O uso de
Tipo1, indica ao compilador que se pode aceitar qualquer tipo (
?) genérico.
Contudo não se pode adicionar elementos à colecção.
Não se pode usar a notação ? (wildcard) na criação de objectos. Apenas é possível nas referências.
Criando classes genéricas (exemplos com classe genérica):
- public class Xpto{... - Qualquer identificador Java é válido
- private List xpto2; -Usar o tipo da classe para o tipo da lista
- public Xpto (List x){... -Construtor que recebe uma lista do tipo da classe
- public T getXpto(){... -Retorna-se T
- public void returnX(T qq)... -Recebe-se T como parâmetro
- T instânciaDeClasse - Como tipo de variável de classe
- T[] array - Como tipo de array
- public class useTwo{ -Dois tipo parametrizados
- public class Bla{... -Género de limitador de tipo
Criando métodos construtores genéricos (exemplos em que a classe não é genérica. Só os métodos):
- public void make(T t){...
- public doda(T t){...
- public Radio(T t){... - Construtor
Convenções na documentação de API's:
- Element (colecções)
- Type (usado em tudo excepto colecções)
Inner Classes
O código na
Inner Class pode aceder aos
membros da
enclosing (outer) class, como se a
inner class fosse parte da
outer class. Uma instância da
inner class tem acesso a
todos os membros da
outer class, incluindo aqueles marcados como
private.
As
inner classes são definidas dentro das
{} da
outer class.
Uma
inner class não pode ter quaisquer declarações
static.
Para se aceder à
inner class tem de ser ter uma instância da
outer class.
Exemplos:
Instanciar uma
inner class de dentro da
outer class:
new InnerClass();
Instanciar uma
inner class de fora da
outer class:
MyOuter.MyInner x = MyOuter.new MyInner(); (*)
Referenciar a
inner class dentro dela própria:
this
Referenciar a instância da
outer class dentro da
inner class:
MyOuter.this
(*) Tem mesmo de se usar o nome da classe. Não se pode usar a instância.
Method-Local Inner Classes
Definida dentro de um método. Só pode ser instanciada dentro do método onde é declarada mas depois da declaração. Pode aceder a todos os membros da
outer class (mesmo os privados). Contudo não consegue ver as variáveis locais do método a não ser que sejam marcadas como
final. Este tipo de classes pode ser criada dentro de métodos estáticos (com as mesmas restrições aplicáveis a métodos estáticos).
Anonymous Inner Classes
Declaram uma nova classe que não tem nome, mas que é uma subclasse do tipo de declarado no
new.
Ex:
Popcorn p = new Popcorn(){....};
Também pode implementar uma interface.
Tomar em atenção que só faz sentido implementar ou fazer overriding a métodos da superclasse, pois a variável de referência é sempre a da interface/superclasse (no exemplo acima:
Popcorn). Contudo é possível fazer overloading ou criar novos métodos. Estes nunca poderão é ser invocados de fora.
Aplicam-se as mesmas regras das
inner classes.
Argument-Defined Anonymous Inner Classes
Definida mesmo dentro de uma chamada a um método como argumento.
Aplicam-se as mesmas regras das
inner classes.
Static Nested Classes
É pura e simplesmente um membro estático da
enclosing class. Aplicam-se todas as restrições dos métodos
static.
Instanciação de fora:
Outer,Nest x = new Outer.Nest();
Instanciação dentro da Outer é feita de modo normal.
Nota:
Tomar em atenção que nas Anonymous Inner Classes e Argument-Defined Anonymous Inner Classes os construtores são invocados! Ex: new Popcorn() - Invoca o construtor vazio. new Popcorn(10) - O construtor recebe um int, etc.
Métodos Principais da classe java.lang.Thread (implements java.lang.Runnable)
- Thread()
- Thread(String name)
- Thread(Runnable) - Neste caso o método run() invocado é o da instância passada.
- Thread(Runnable, String name) - Neste caso o método run() invocado é o da instância passada.
- public void run() - A classe Thread espera que exista o método run() sem argumentos, e executa este método numa chamada separada (numa stack diferente) depois da thread começar. Este método é invocado pelo start().
- start() - Invoca o método run(). Começa a nova thread de execução. A thread passa para o estado Runnable. Assim que poder executar invoca o run(). O método start() apenas pode ser invocado uma vez. Uma IllegalThreadStateException (não checada) é atirada se o método for invocado mais do que uma vez.
- boolean isAlive() - true se o método start() já foi invocado; false caso start() ainda não tenha sido invocado ou se o método run() já terminou.
- public final void join() throws InterruptedException - Faz com que uma thread espere até que a outra entre no estado Dead.
- String getName() - Devolve o nome da thread
- static Thread currentThread() - Devolve a corrente thread de execução
- void setName(String)
- long getId() - Devolve o id da thread
- static void sleep(long milis) throws InterruptedException - (*)
- static void yeld() - Faz com que a thread passe do estado Running para o estado Runnable. Nada é garantido [dependa da JVM] (*)
- public final setPriority(int) - Inteiro entre 1 e 10 (depende a JVM).
(*) - Não libertam os locks
Métodos Principais da Interface java.lang.Runnable
- public void run() - Comportamento igual ao método run() da classe Thread. É invocado pelo start().
Para correr uma
Runnable:
- Criar a classe que implementa Runnable
- Passar a instância para dentro de uma nova Thread (new Thread(Runnable))
Nota :
Tomar em atenção que a invocação directa do método run() (sem ser pelo start()) não cria um nova thread de execução!
Continua....